views:

115

answers:

5

Another c++ pointer deletion question is in the following example:

class Foo {
public:
    int *p;
    ~Foo() {
        delete p; p = NULL;
    }
};

Foo *f1 = new Foo();
Foo *f2 = new Foo();
f1->p = new int(1);
f2->p = f1->p;
delete f2; // ok
delete f1; // no error?

Why I did not get error when calling "delete f1"? didn't I delete the same address (*p) twice?

If I directly delete the pointers in the last 2 lines of code, I will get error.

delete f2->p; // ok
delete f1->p; // error!! *** glibc detected *** double free or corruption (fasttop) ***
+5  A: 

It is a VERY bad thing to do. However C++ won't necessarily do anything here. It is "un-defined" behaviour. That doesn't mean it will crash but it will, most probably, cause bad shit (tm) to happen.

Edit: Furthermore in your 2nd example the fact it crashes is just a part of "undefined" behaviour. It is undefined as to what the reaction will be.

Goz
I have voted -1 and am very sorry for that. if you just edited your post, I would be able to remove my downvote. Again, I am very sorry, my bad
Armen Tsirunyan
@Armen: Updated :)
Goz
@Goz: Upvoted. Again, sorry for voting without much thinking :)
Armen Tsirunyan
@Armen: No probs. It happens :)
Goz
+3  A: 

Trust me, you don't want to do that.

Take a look at boost::shared_ptr: it allows you to deal with pointers in an elegant way, without having to care too much about their deletion.

class Foo {
public:
    boost::shared_ptr<int> p;
};

Foo *f1 = new Foo();
Foo *f2 = new Foo();
f1->p.reset(new int(1));
f2->p = f1->p;
delete f2; // ok
delete f1; // no error and its guaranteed !

If you don't want to use boost, some compilers already provide std::tr1::shared_ptr which has similar semantics.

ereOn
@ereOn - this won't compile as is, check my code for working `f1` setup
Steve Townsend
Isn't std::tr1::shared_ptr *the* boost::shared_ptr?
Mark Ingram
@Steve Townsend: Thanks for noticing the typo. Indeed `reset()` takes a pointer.
ereOn
@Mark Ingram: I wouldn't say for sure, but I believe that `std::tr1::shared_ptr` implementation depends on the compiler vendor and is not mandatorily the same than `boost`.
ereOn
+1  A: 

If you want to use multiple pointers to the same memory, encapsulate them in boost::shared_ptr, which will ensure that the underlying memory is not delete-d until the last reference to it goes out of scope.

#include <boost/shared_ptr.hpp>

class Foo {
public:
    boost::shared_ptr<int> p;
    ~Foo() {
      p.reset();
    }
};

Foo *f1 = new Foo();
Foo *f2 = new Foo();
f1->p.reset(new int(1));
f2->p = f1->p;
delete f2; // ok
delete f1; // no error
Steve Townsend
`p` destructor will release the pointer anyway. The explicit `~Foo` destructor is really not needed here.
ereOn
@ereOn, thanks - I think this is clearer in the context of the original code.
Steve Townsend
+3  A: 

Why I did not get error when calling "delete f1"? didn't I delete the same address (*p) twice?

Yes you did delete that object twice.

However, the outcome of that is Undefined Behavior. That could result in the run-time system catching the error and popping up a message, but it could just as well result in your HD getting formatted, nasty Nasal Demons chasing you around the office to the delight of your fellow-workers, or you or your girlfriend getting pregnant. Or then it might also appear to "work", whatever that means in this case.

sbi
A: 
Will