Sign in to follow this  
Raeldor

Smart Pointers and 'delete'

Recommended Posts

I have written by own smart pointer class which seems to work quite well, but it seems smart pointers should never have 'delete' called on them (unless they are allocated with new), as this seems to delete the object that the pointer is pointer to (conversion?). Is there a way to stop or trap delete being called on the smart pointer? How do other libraries stop people doing this? Thanks

Share this post


Link to post
Share on other sites
If you don't provide an implicit conversion to the underlying pointer type the statement delete smartPointer; becomes a compile error. And it's great that you've written your own smart pointer. Now that you've learnt how to write one, throw it away and use the (soon to be standard) boost smart pointers.

Enigma

Share this post


Link to post
Share on other sites
Quote:
Original post by Enigma
If you don't provide an implicit conversion to the underlying pointer type the statement delete smartPointer; becomes a compile error. And it's great that you've written your own smart pointer. Now that you've learnt how to write one, throw it away and use the (soon to be standard) boost smart pointers.

Enigma


I'd like to finish my implementation first. I do have a conversion function, so I am not getting a compile error, but I am assuming that it is converting to a true pointer of the underlying type, thus deleting the object. Surely this can't happen if there are other references, so how do I stop it? Do I need to put assert code into the base object's destructor to assert if the reference count is not zero?

Share this post


Link to post
Share on other sites
You need to not have a conversion operator. When the compiler sees the statement delete pointer; it first checks to see if pointer is of type (anything) *. If not it looks to see if it can convert pointer to an (anything) *. If your smart pointer class provides a operator TYPE *() and/or operator TYPE const *() const then the compiler will apply this conversion, making the original statement equivalent to delete (pointer.operator TYPE *()) and will therefore delete the returned pointer. The only way to disallow this is to not provide the conversion operator but instead provide a named member function to access the raw pointer (i.e. get()).

Enigma

Share this post


Link to post
Share on other sites
I usually never explicitly delete objects contained in smart pointer. I use smart pointers to avoid having to think about deleting objects.
But in the case where I need to control the explicity deletion of an object, I simply assign NULL or 0 to the smart pointer. The overloaded assignment operator handles the deletion internally. It also makes code more generic as it works the same for refcounted smart pointers.

Share this post


Link to post
Share on other sites
Quote:
Original post by Blaster
I usually never explicitly delete objects contained in smart pointer. I use smart pointers to avoid having to think about deleting objects.
But in the case where I need to control the explicity deletion of an object, I simply assign NULL or 0 to the smart pointer. The overloaded assignment operator handles the deletion internally. It also makes code more generic as it works the same for refcounted smart pointers.


I hear what you are saying, but when you are dealing with both smart pointers and regular pointers it's easy to accidentally have a delete on a smart pointer. Would be nice if there was a way to trap this to avoid memory errors.

Share this post


Link to post
Share on other sites
I would have recommended making operator delete() private in the smart pointer but that would simply prevent deleting a smartpointer*, not calling delete with a smartpointer&.
A private destructor would not allow local allocation or making the object a member.
I am clueless sorry.

Share this post


Link to post
Share on other sites
Making the destructor private also stops you from using the smart pointer at all.

IMHO don't worry about it. It's standard practice that you don't call delete on smart pointers. If you're really that concerned about it then maybe you can provide your own operator delete for the smart pointer class.

Share this post


Link to post
Share on other sites
Quote:
Original post by Anon Mike
Making the destructor private also stops you from using the smart pointer at all.

IMHO don't worry about it. It's standard practice that you don't call delete on smart pointers. If you're really that concerned about it then maybe you can provide your own operator delete for the smart pointer class.


Do the base destructors always get called for sub-classes when the destructor is virtual, or do I need to call it myself from the sub-class?

Share this post


Link to post
Share on other sites
If the destructor is not virtual and you call delete on the final object (the most derived class), everything will be called.

But if it's not virtual and you call delete on one of the base class, it will not execute the destructor of the derived classes.

Basically if it's a base class and destructor is public, make it virtual.

Share this post


Link to post
Share on other sites
Quote:
Original post by Blaster
But if it's not virtual and you call delete on one of the base class, it will not execute the destructor of the derived classes.


The behaviour is undefined, never take trip to the land of undefined....

Quote:
Original post by Blaster
Basically if it's a base class and destructor is public, make it virtual.


Thats being abit hasty, better advice would be:

if you intend on invoking delete on pointers to base types then make the base type's destructor (pure) virtual.

Share this post


Link to post
Share on other sites
snk_kid: Your improvements on my comments are very good. You made me think, thank you.
But hey, I must be a hasty fellow :)

++rank

Share this post


Link to post
Share on other sites


struct int_struct
{
int i;
};

template<class T>
class smart_ptr
{
public:
explicit smart_ptr(T* value);

T& operator*(){return *_value;}//add null checking before using
T* operator->(return _value;)

//instead of:
operator T* (){return _value;}

//you want something like this:
const T* get()const{return _value;}

//and possibly
T* release(){/*something a little more complicated*/}
};

//Now:

smart_ptr<int_struct> a = smart_ptr<int_struct>(new int_struct);

delete a;//compiler error
delete a.get();//compiler error

std::cout << a->i;//fine
a->i = 5;//fine
*a.i = 5;//fine




That does what you want. You obviously need to add the rest of the implementation.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this