my smart pointer!

Saludos... This is my very first post here. Hope find some help. I'm a IT student from Venezuela and was assigned the project of creating a Utility library as home project. It should tackle the problems we find in C code, for example, with arrays we have no range check, acquired resourses like memory chunks that we forget to free, keeping the window open in certain environmen and such. I'm creating my version of a smart pointer but can't figured out some things, here's the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
template<typename type>
class puntero
{
public:
	explicit puntero(type* var = 0)
		: p(var){ }
	
	~puntero()
	{ 
					
	   if(p) delete p;
	   p = 0;
					
	}
	type& operator*() 
	{ 
		if(p) return (*p);
		throw puntero_nulo();

	}
	void operator =(type * tp) 
	{
		p = tp; // Aqui falta algo....
	}

	

private:
	type * p;
};


The idea is to create a pointer that u can use like a regular one but safer. U can create it first with resourses on the heap but assign it to a variable on the stack with no problem of memory leak of a notify. Although i acknowlage threres something missing in in the code for the dereference and the assignement operator i could figure them out but i cannot think of how to make my pointer show the address of the variable it is pointing at, like:
1
2
3
puntero<int> intptr(new int(0) );
std::cout << intptr << std::endl;
// The second line sould print a memory address, 0002a4f78 or something 
. It's the only thing left to do in my library, well that and how to keep the window open! I saw some nice ideas here like:
1
2
3
4
5
#include <limits>

std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Press Enter......" << std::endl;
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n');



But my problem with that is that u have to include another library for that. Then you have others like
1
2
3
4
5
6
7
8
9
10
std::cin.get(); which you you might have to write twice;

std::cin.get(); 
std::cin.get();  or

char c(0);
std::cin.get(c).get(c);

doesnt look quite fine!


Ok almost forget the dereferen operator in my pointer throws a "puntero_nulo" like a Null pointer exception, here's the code:

1
2
3
4
5
6
7
8
9
10
11
12
struct puntero_nulo: public std::exception
{
	
	puntero_nulo(std::string msg = "<NULL POINTER> atline:"):line(__LINE__),  _msg( msg ),
		exception( msg.c_str() )
	{  }

private:
	const int line;
	std::string _msg;
	
};


In the exception i want to report the line where the null pointer ocurred. But that is the trickiest one!!!!
Hope some of you might have some nice ideas.....
Hasta luego!

First question. Why are you reinventing boost::scoped_ptr? Why not just use it? Or boost::shared_ptr, boost::weak_ptr, or std::auto_ptr?

Secondly,

1
2
3
4
5
6
7
template<typename type>
class puntero
{
  public:
    friend std::ostream& operator<<( std::ostream& os, const puntero& ptr )
        { return os << ptr.p; } 
};


Thirdly, operator= should return a puntero&, not void, although operator= is not usable
in its current form, since the following code will corrupt the heap due to a double free:

1
2
3
puntero<int> pi( new int );
puntero<int> pi2;
pi2 = pi;


Fourthly, you have the same heap corruption problem with the copy constructor as with
operator=.

Fifthly, there isn't a way to output the line number without forcing additional syntactic
baggage onto the user of your type (ie, creating a macro).

Lastly, use the boost smart_ptr library or std::auto_ptr; don't reinvent them.
@jsmith "Tis an issignment, for pedagogical reasons i guess, maybe his or her teacher already knows boost ant the auto_ptr thing!!!

Ok, since it's about tring to clarify things let's get to it. Like this it's no way a safe pointer. Consider:

1
2
3
4
5
puntero<int> int_ptr(new int(0) );

int int_var = 100;
int_ptr = &int_var; // ouch, what u are trying to avoid actually happens
 


The thing is that ur assignement operator in fact made ur pointer point at another variable on the stack but it never went outta scope so the desctructor to realease the resourse on the heap was never called, memory leak. You have to call the destructor from the assingment operator to avoid that, would ne something like this:
1
2
3
4
5
6
7
// it doesnt make much a diferen it return void in this case in fact u might find some problems returning "this"...
void operator =(type * tp) 
	{
		this->~puntero(); // free memory before new assigments...
		p = tp; 
	}


Now we have another problem, when the pointer actually goes outta scope will call the destructor again!!! Trying to release memory on the heap that doesnt exist if actually the second assinment was to a variable on the stack, nasty thing!!!! You have to make yr destructor aware od such things with something like this maybe:

1
2
3
4
5
6
7
~puntero()
{ 
	static int guard = 0;
	if(p && !guard) delete p;
	p = 0;
	guard++;
}

You have to specify for the users this:
The restriction is to create a dynamic variable only the first time then safely assign to another variable on the stack, NOT ANOTHER DYNAMIC VARIABLE! But then why would u want to do that??!!

That's the kind of things that happens trying to tame pointers!

To print the adress of ur pointer well Jsmith already told u how!

But now, what if i want to do this??

1
2
puntero<int> *iptr;
// add this feature 


With respect to keeping the window open i made myself this:

1
2
3
4
5
6
7
8
9

inline void pause_scr()
{
    std::cout << "Press <ENTER> To Quit!" << std::endl;
    std::cin.ignore( std::cin.rdbuf()->in_avail() +1 );
}

// No need for extra "includes"!!!!!!


There is a way to print the line but it's a lot of work trust me...

Good luck!
puntero(type* var = 0) Is there a way to assure that var point to a valid position? Or, better, that its the result of a new operation.


1
2
//puntero& operator =(type * tp) 
puntero & operator = (puntero<type> *tp) // I think this its safer  

Check http://ootips.org/yonat/4dev/smart-pointers.html to different ways to handle that. (I think that you could have a wrapper object and use observer too)


By the way: why std::auto_ptr has an get() method? you could corrupt everything with
delete ptr.get();
Last edited on
puntero(type* var = 0) Is there a way to assure that var point to a valid position? Or, better, that its the result of a new operation.


Well I think the assurance so to speak is given by the dereference operator in which it checks thats not a null pointer before derefencing it! The constructor is explicit and pretty straight foward it expects either a "&variable" or the result of a new operator like:

1
2
3
4
5
6
float fvar(0.0F);
puntero<float> fptr(&fvar); // But this will bring up a new problem!!! is there a way to avoid it?
//or
puntero<float> ffptr(new float(0.0F) );
//which is what we want!
//remember is to avoid memory leaks 


The problem I comment above has to do when it comes outta scope, again it will try to free non-existent memoru on the heap!

That's why the specification should say it's for creating dynamic avriables the first time



//puntero& operator =(type * tp)
puntero & operator = (puntero<type> *tp) // I think this its safer


No way!!!!!!!!!!!! That would on the other hand be a bad idea, actually, cuz it would complicate
something thats already what we want!

if you want to return something from the assignement operator do this:

1
2
3
4
type* operator=(type * var);
// the class is just a wrapper what we want is "type*"!!!
//dont return puntero<type>&
//remember we want to assign after to native pointer to call it a way.... 


This piece that fallows would serve 2 perposes at least and then some risks like with everything

1
2
3
4
5

operator type*()
{
   return p;
}

That allows to do things like:
1
2
3
4
5
6
7
8
9
10
11
int* ptr2int = 0;
puntero<int> iptr(new int(0) );

std::cout << iptr << std::endl; // Address
// without overloading "<<" operator!

//and

ptr2int = iptr;

// trying to make "puntero<int>" much more like a built-in. 


But again it's about pointer and there a huge responsability on the programmers always!!!



Lastly I pointed to be able to do something like this:

 
puntero<int> *iptr;


Ideas??




Hey, thanx everyone for your replies.... at last i finished that up! I worked out everything else about copy cntr, iquality operator and such.

@DemienBjarne: I'd never would've thought of that level of details , thanx man!


1
2
operator =(type * tp)
operator = (puntero &tp)

It's not about the return value, it's about the parameters that receives (sorry I've got a typo in the first version).
The idea it's to not allow that p points to garbage (NULL it's not the only one who causes problems).
If you're going to trust just in the documentation use raw pointers then.

remember we want to assign after to native pointer to call it a way....

That has nothing to do with operator=, it's a getter instead.

Also you're forgetting how to handle if two o more smart_pointers point to the same direction: must be deleted only one time and after that all point to NULL.
Last edited on
I totally understand your point. Programmers sometimes dont have the freedom to do what we think is best but we have to abide by specifcations. By what i read he was asked to make a pointer as close as posssible to a raw one and take care of some dangers like memory leak and "null dereference", that was attained. On my part i would add more checking of course...

That has nothing to do with operator=, it's a getter instead.


You mean a getter like "ptr.get()" kinda thing. Well the thing is that that doesnt look much like a raw pointer!! And the very point of overloading operator is make our own types look as much close posible to built-in types!!!

Topic archived. No new replies allowed.