Do I need to nullify a member variable in the destructor? - c++

Why one would want to explicitly clear the a vector member variable (of on in a dtor (please see the code below). what are the benefits of clearing the vector, even though it will be destroyed just after the last line of dtor code will get executed?
class A
{
~A()
{
values.clear();
}
private:
std::vector < double > values_;
};
similar question about a the following code:
class B
{
~B()
{
if (NULL != p)
{
delete p_;
p_ = NULL;
}
}
private:
A * p_;
};
Since there is no way the dtor will get called twice, why to nullify p_ then?

In class A, there is absolutely no reason to .clear() the vector-type member variable in the destructor. The vector destructor will .clear() the vector when it is called.
In class B, the cleanup code can simply be written as:
delete p_;
There is no need to test whether p_ != NULL first because delete NULL; is defined to be a no-op. There is also no need to set p_ = NULL after you've deleted it because p_ can no longer be legitimately accessed after the object of which it is a member is destroyed.
That said, you should rarely need to use delete in C++ code. You should prefer to use Scope-Bound Resource Management (SBRM, also called Resource Acquisition Is Initialization) to manage resource lifetimes automatically.
In this case, you could use a smart pointer. boost::scoped_ptr and std::unique_ptr (from C++0x) are both good choices. Neither of them should have any overhead compared to using a raw pointer. In addition, they both suppress generation of the implicitly declared copy constructor and copy assignment operator, which is usually what you want when you have a member variable that is a pointer to a dynamically allocated object.

In your second example there's no reason to set p_ to null whatsoever, specifically because it is done in the destructor, meaning that the lifetime of p_ will end immediately after that.
Moreover, there's no point in comparing p_ to null before calling delete, since delete expression performs this check internally. In your specific artificial example, the destructor should simply contain delete p_ and noting else. No if, no setting p_ to null.

In the case of p_, there is no need to set it equal to null in the destructor, but it can be a useful defensive mechanism. Imagine a case where you have a bug and something still holds a pointer to a B object after it has been deleted:
If it trys to delete the B object, p_ being null will cause that second delete to be innocuous rather than a heap corruptor.
If it trys to call a method on the B object, p_ being null will cause a crash immediately. If p_ is still the old value, the results are undefined and it may be hard to track down the cause of the resulting crash.

Related

Dangling Pointers after Destructor is called

I went through this post and had a doubt. Is it a good practice to null an element of an object in its destructor?
The destructor will be called when the object goes out of scope but will its elements need to be set to NULL in the destructor to ensure dangling pointers are not left.
After an object is destroyed, it ceases to exist. There is no point in setting its members to particular values when those values will immediately cease to exist.
The pattern of setting pointers to NULL when deleteing the objects they point to is actively harmful and has caused errors in the past. Unless there's a specific reason the pointer needs to be set to NULL (for example, it is likely to be tested against NULL later) it should not be set to NULL.
Consider:
Foo* foo getFoo();
if (foo!=NULL)
{
do_stuff();
delete foo;
}
// lots more code
return (foo == NULL);
Now, imagine if someone adds foo = NULL; after the delete foo; in this code, thinking that you're supposed to do that. Now the code will give the wrong return value.
Next, consider this:
Foo* foo getFoo();
Foo* bar = null;
if (foo != NULL)
{
bar = foo;
do_stuff(bar);
delete bar;
bar = NULL;
}
// lots more code
delete foo;
We always set pointers to NULL after we delete them, so this delete foo; must be safe, right? Clearly it's not. So setting pointers to NULL after you delete them is neither necessary nor sufficient.
Don't do it.
It's not necessary to set member elements to NULL in the destructor, as delete has been called on the owner object in order for that destructor to be called. It is the responsibility of the code that deletes an object to no longer try to access the contents of that object.
You are also using extra cycles clearing out that memory.
The point of doing this is to provide deterministic behavior in event of a programming error.
If the deleted pointer is used, then the program will always fail on dereferencing a nullptr. (Not allowing the program to continue.)
If the deleted pointer set to nullptr and is then deleted again, then the second attempt is a noop (by design).
This is the normal pattern for pointers that are NOT deleted in a destructor. (Smart pointers are your friend, to avoid this situation, entirely.)
The purpose of nulling a deleted member pointer in a destructor is less obvious; when there is a suspicion that other code may have a reference to that member. This should generally be avoided (to rely on this), because it has limited utility once the memory for the destructed class is reclaimed. Although implementation dependent, in many environments the memory can live long enough to cause the program to fail when the deleted memory is re-used, so that the programmer can find the issue and fix it.

Destructor and smart pointers giving C2541

I'm trying to use some vectors of shared_ptr in my program, but doing so gives me a C2541-error: "delete": objects that are no pointers can't be deleted. I figured out it has something to do with the destructors of my classes (at least with one of them...) so i tried changing them - without success :(
My application contains a class A, which holds two vectors: one of shared_ptrs to objects of class B and of shared_ptrs to objects of class A.
Here are some parts of my code:
//A.cpp
A::~A(void)
{
for(std::vector<BPtr>::iterator it = allBs.begin(); it != allBs.end(); ++it)
{ //loop that deletes all Bs
delete it->get();
}
for(std::vector<APtr>::iterator it = allAs.begin(); it != allAs.end(); ++it)
{ //loop that (should) delete all As (and their As and Bs)
delete it->get();
delete it.operator*;
}
}
//A.h
class A
{
public:
typedef std::shared_ptr<A> APtr;
typedef std::shared_ptr<B> BPtr;
// some more stuff
private:
std::vector<BPtr> allBs;
std::vector<APtr> allAs;
}
I'm getting the error twice: one comes from the line
delete it.operator*;
and the other one is caused inside of memory.h.
I first had an extra recursive function which deleted the tree and was called by the destructor, but after a little thinking I thought that calling "delete" inside the destructor (line "delete it->get();") would do just the same.
You're doing it wrong.
The entire purpose of smart pointers like std::shared_ptr is that you do not have to manually delete what they point at. Indeed, you must not delete it manually. The smart pointer assumes ownership of the pointee—it will delete it itself when applicable. For std::shared_ptr, "when applicable" means "when the last std::shared_ptr pointing to the object is destroyed."
So just remove the destructor altogether, you don't need it. When the vectors are destroyed, they will destroy all of the contained std::shared_ptrs. This will reduce the reference count of the pointees. If any go to zero, they will be deleted automatically (by the shared_ptr destructor).
You don't want to delete a shared_ptr's contents, that's its job. simply reset the smart pointer:
it->reset();
You can and must delete only things created with new. Only these exactly once, nothing else. Deletion can be done either "by hand" or by letting a smart pointer like std::shared_ptr do it for you (which is a very good idea). When using smart pointers, you can (and should) get rid of the new in favor of std::make_shared or std::make_unique.
The same applies to new[] and delete[].
This means that in your destructor there is no room for delete because you never newed anything and have it owned by a raw pointer (which was good).

Stack Overflow when deleting this Pointer

I have the following code and I get stack overflow error can anyone please explain me What's wrong here. from my understanding this pointer points to current object so why I cant delete it in a destructor;
class Object
{
private:
static int objCount;
public:
int getCount()
{
int i =10;
return i++;
}
Object()
{
cout<< "Obj Created = "<<++objCount<<endl;
cout <<endl<<this->getCount()<<endl;
}
~Object()
{
cout<<"Destructor Called\n"<<"Deleted Obj="<<objCount--<<endl;
delete this;
}
};
int Object::objCount = 0;
int _tmain(int argc, _TCHAR* argv[])
{
{
Object obj1;
}
{
Object *obj2 = new Object();
}
getchar();
return 0;
}
You're doing delete this; in your class's destructor.
Well, delete calls the class's destructor.
You're doing delete this; in your class's destructor.
...
<!<!<!Stack Overflow!>!>!>
(Sorry guys I feel obliged to include this... this might probably spoil it sorrrryyyy!
Moral of the boring story, don't do delete this; on your destructor (or don't do it at all!)
Do [1]
Object *obj = new Object();
delete obj;
or much better, just
Object obj;
[1]#kfsone's answer more accurately points out that the stack overflow was actually triggered by obj1's destructor.
'delete this' never makes sense. Either you're causing an infinite recursion, as here, or you're deleting an object while it is still in use by somebody else. Just remove it. The object is already being deleted: that's why you're in the destructor.
The crash you are having is because of the following statement:
{
Object obj1;
}
This allocates an instance of "Object" on the stack. The scope you created it in ends, so the object goes out of scope, so the destructor (Object::~Object) is invoked.
{
Object obj1;
// automatic
obj1.~Object();
}
This means that the next instruction the application will encounter is
delete this;
There are two problems right here:
delete calls the object's destructor, so your destructor indirectly calls your destructor which indirectly calls your destructor which ...
After the destructor call, delete attempts to return the object's memory to the place where new obtains it from.
By contrast
{
Object *obj2 = new Object();
}
This creates a stack variable, obj2 which is a pointer. It allocates memory on the heap to store an instance of Object, calls it's default constructor, and stores the address of the new instance in obj2.
Then obj2 goes out of scope and nothing happens. The Object is not released, nor is it's destructor called: C++ does not have automatic garbage collection and does not do anything special when a pointer goes out of scope - it certainly doesn't release the memory.
This is a memory leak.
Rule of thumb: delete calls should be matched with new calls, delete [] with new []. In particular, try to keep new and delete in matching zones of authority. The following is an example of mismatched ownership/authority/responsibility:
auto* x = xFactory();
delete x;
Likewise
auto* y = new Object;
y->makeItStop();
Instead you should prefer
// If you require a function call to allocate it, match a function to release it.
auto* x = xFactory();
xTerminate(x); // ok, I just chose the name for humor value, Dr Who fan.
// If you have to allocate it yourself, you should be responsible for releasing it.
auto* y = new Object;
delete y;
C++ has container classes that will manage object lifetime of pointers for you, see std::shared_ptr, std::unique_ptr.
There are two issues here:
You are using delete, which is generally a code smell
You are using delete this, which has several issues
Guideline: You should not use new and delete.
Rationale:
using delete explicitly instead of relying on smart pointers (and automatic cleanup in general) is brittle, not only is the ownership of a raw pointer unclear (are you sure you should be deleting it ?) but it is also unclear whether you actually call delete on every single codepath that needs it, especially in the presence of exceptions => do your sanity (and that of your fellows) a favor, don't use it.
using new is also error-prone. First of all, are you sure you need to allocate memory on the heap ? C++ allows to allocate on the stack and the C++ Standard Library has containers (vector, map, ...) so the actual instances where dynamic allocation is necessary are few and far between. Furthermore, as mentioned, if you ever reach for dynamic allocation you should be using smart pointers; in order to avoid subtle order of execution issues it is recommend you use factory functions: make_shared and make_unique (1) to build said smart pointers.
(1) make_unique is not available in C++11, only in C++14, it can trivially be implemented though (using new, of course :p)
Guideline: You shall not use delete this.
Rationale:
Using delete this means, quite literally, sawing off the branch you are sitting on.
The argument to delete should always be a dynamically allocated pointer; therefore should you inadvertently allocate an instance of the object on the stack you are most likely to crash the program.
The execution of the method continues past this statement, for example destructors of local objects will be executed. This is like walking on the ghost of the object, don't look down!
Should a method containing this statement throw an exception or report an error, it is difficult to appraise whether the object was successfully destroyed or not; and trying again is not an option.
I have seen several example of usage, but none that could not have used a traditional alternative instead.

Check for non-deallocated pointer

Assume a pointer object is being allocated on one point and it is being returned to different nested functions. At one point, I want to de-allocate this pointer after checking whether it is valid or already de-allocated by someone.
Is there any guarantee that any of these will work?
if(ptr != NULL)
delete ptr;
OR
if(ptr)
delete ptr;
This code does not work. It always gives Segmentation Fault
#include <iostream>
class A
{
public:
int x;
A(int a){ x=a;}
~A()
{
if(this || this != NULL)
delete this;
}
};
int main()
{
A *a = new A(3);
delete a;
a=NULL;
}
EDIT
Whenever we talk about pointers, people start asking, why not use Smart Pointers.
Just because smart pointers are there, everyone cannot use it.
We may be working on systems which use old style pointers. We cannot convert all of them to smart pointers, one fine day.
if(ptr != NULL) delete ptr;
OR
if(ptr) delete ptr;
The two are actually equivalent, and also the same as delete ptr;, because calling delete on a NULL pointer is guaranteed to work (as in, it does nothing).
And they are not guaranteed to work if ptr is a dangling pointer.
Meaning:
int* x = new int;
int* ptr = x;
//ptr and x point to the same location
delete x;
//x is deleted, but ptr still points to the same location
x = NULL;
//even if x is set to NULL, ptr is not changed
if (ptr) //this is true
delete ptr; //this invokes undefined behavior
In your specific code, you get the exception because you call delete this in the destructor, which in turn calls the destructor again. Since this is never NULL, you'll get a STACK OVERFLOW because the destructor will go uncontrollably recursive.
Do not call delete this in the destructor:
5.3.5, Delete: If the value of the operand of the delete-expression is not a null pointer value, the delete-expression will
invoke the destructor (if any) for the object or the elements of the array being deleted.
Therefore, you will have infinite recursion inside the destructor.
Then:
if (p)
delete p;
the check for p being not null (if (x) in C++ means if x != 0) is superfluous. delete does that check already.
This would be valid:
class Foo {
public:
Foo () : p(0) {}
~Foo() { delete p; }
private:
int *p;
// Handcrafting copy assignment for classes that store
// pointers is seriously non-trivial, so forbid copying:
Foo (Foo const&) = delete;
Foo& operator= (Foo const &) = delete;
};
Do not assume any builtin type, like int, float or pointer to something, to be initialized automatically, therefore, do not assume them to be 0 when not explicitly initializing them (only global variables will be zero-initialized):
8.5 Initializers: If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an
object with automatic or dynamic storage duration has indeterminate value. [ Note: Objects with static or thread storage duration are zero-initialized
So: Always initialize builtin types!
My question is how should I avoid double delete of a pointer and prevent crash.
Destructors are ought to be entered and left exactly once. Not zero times, not two times, once.
And if you have multiple places that can reach the pointer, but are unsure about when you are allowed to delete, i.e. if you find yourself bookkeeping, use a more trivial algorithm, more trivial rules, or smart-pointers, like std::shared_ptr or std::unique_ptr:
class Foo {
public:
Foo (std::shared_ptr<int> tehInt) : tehInt_(tehInt) {}
private:
std::shared_ptr<int> tehInt_;
};
int main() {
std::shared_ptr<int> tehInt;
Foo foo (tehInt);
}
You cannot assume that the pointer will be set to NULL after someone has deleted it. This is certainly the case with embarcadero C++ Builder XE. It may get set to NULL afterwards but do not use the fact that it is not to allow your code to delete it again.
You ask: "At one point, I want to de-allocate this pointer after checking whether it is valid or already de-allocated by someone."
There is no portable way in C/C++ to check if a >naked pointer< is valid or not. That's it. End of story right there. You can't do it. Again: only if you use a naked, or C-style pointer. There are other kinds of pointers that don't have that issue, so why don't use them instead!
Now the question becomes: why the heck do you insist that you should use naked pointers? Don't use naked pointers, use std::shared_ptr and std::weak_ptr appropriately, and you won't even need to worry about deleting anything. It'll get deleted automatically when the last pointer goes out of scope. Below is an example.
The example code shows that there are two object instances allocated on the heap: an integer, and a Holder. As test() returns, the returned std::auto_ptr<Holder> is not used by the caller main(). Thus the pointer gets destructed, thus deleting the instance of the Holder class. As the instance is destructed, it destructs the pointer to the instance of the integer -- the second of the two pointers that point at that integer. Then myInt gets destructed as well, and thus the last pointer alive to the integer is destroyed, and the memory is freed. Automagically and without worries.
class Holder {
std::auto_ptr<int> data;
public:
Holder(const std::auto_ptr<int> & d) : data(d) {}
}
std::auto_ptr<Holder> test() {
std::auto_ptr<int> myInt = new int;
std::auto_ptr<Holder> myHolder = new Holder(myInt);
return myHolder;
}
int main(int, char**) {
test(); // notice we don't do any deallocations!
}
Simply don't use naked pointers in C++, there's no good reason for it. It only lets you shoot yourself in the foot. Multiple times. With abandon ;)
The rough guidelines for smart pointers go as follows:
std::auto_ptr -- use when the scope is the sole owner of an object, and the lifetime of the object ends when the scope dies. Thus, if auto_ptr is a class member, it must make sense that the pointed-to object gets deletes when the instance of the class gets destroyed. Same goes for using it as an automatic variable in a function. In all other cases, don't use it.
std::shared_ptr -- its use implies ownership, potentially shared among multiple pointers. The pointed-to object's lifetime ends when the last pointer to it gets destroyed. Makes managing lifetime of objects quite trivial, but beware of circular references. If Class1 owns an instance of Class2, and that very same instance of Class2 owns the former instance of Class1, then the pointers themselves won't ever delete the classes.
std::weak_ptr -- its use implies non-ownership. It cannot be used directly, but has to be converted back to a shared_ptr before use. A weak_ptr will not prevent an object from being destroyed, so it doesn't present circular reference issues. It is otherwise safe in that you can't use it if it's dangling. It will assert or present you with a null pointer, causing an immediate segfault. Using dangling pointers is way worse, because they often appear to work.
That's in fact the main benefit of weak_ptr: with a naked C-style pointer, you'll never know if someone has deleted the object or not. A weak_ptr knows when the last shared_ptr went out of scope, and it will prevent you from using the object. You can even ask it whether it's still valid: the expired() method returns true if the object was deleted.
You should never use delete this. For two reasons, the destructor is in the process of deleting the memory and is giving you the opportunity to tidy up (release OS resources, do a delete any pointers in the object that the object has created). Secondly, the object may be on the stack.

explicit destructor

The following code is just used to illustrate my question.
template<class T>
class array<T>
{
public:
// constructor
array(cap = 10):capacity(cap)
{element = new T [capacity]; size =0;}
// destructor
~array(){delete [] element;}
void erase(int i);
private:
T *element;
int capacity;
int size;
};
template<class T>
void class array<T>::erase(int i){
// copy
// destruct object
element[i].~T(); ////
// other codes
}
If I have array<string> arr in main.cpp. When I use erase(5), the object of element[5] is destroyed but the space of element[5] will not be deallocated, can I just use element[5] = "abc" to put a new value here? or should I have to use placement new to put new value in the space of element [5]?
When program ends, the arr<string> will call its own destructor which also calls delete [] element. So the destructor of string will run to destroy the object first and then free the space. But since I have explicitly destruct the element[5], does that matter the destructor (which is called by the arr's destuctor) run twice to destruct element[5]? I know the space can not be deallocated twice, how about the object? I made some tests and found it seems fine if I just destruct object twice instead of deallocating space twice.
Update
The answers are:
(1)I have to use placement new if I explicitly call destructor.
(2) repeatedly destructing object is defined as undefined behavior which may be accepted in most systems but should try to avoid this practice.
You need to use the placement-new syntax:
new (element + 5) string("abc");
It would be incorrect to say element[5] = "abc"; this would invoke operator= on element[5], which is not a valid object, yielding undefined behavior.
When program ends, the arr<string> will call its own destructor which also calls delete [] element.
This is wrong: you are going to end up calling the destructor for objects whose destructors have already been called (e.g., elements[5] in the aforementioned example). This also yields undefined behavior.
Consider using the std::allocator and its interface. It allows you easily to separate allocation from construction. It is used by the C++ Standard Library containers.
Just to explain further exactly how the UD is likely to bite you....
If you erase() an element - explicitly invoking the destructor - that destructor may do things like decrement reference counters + cleanup, delete pointers etc.. When your array<> destructor then does a delete[] element, that will invoke the destructors on each element in turn, and for erased elements those destructors are likely to repeat their reference count maintenance, pointer deletion etc., but this time the initial state isn't as they expect and their actions are likely to crash the program.
For that reason, as Ben says in his comment on James' answer, you absolutely must have replaced an erased element - using placement new - before the array's destructor is invoked, so the destructor will have some legitimate state from which to destruct.
The simplest type of T that illustrates this problem is:
struct T
{
T() : p_(new int) { }
~T() { delete p_; }
int* p_;
};
Here, the p_ value set by new would be deleted during an erase(), and if unchanged when ~array() runs. To fix this, p_ must be changed to something for which delete is valid before ~array() - either by somehow clearing it to 0 or to another pointer returned by new. The most sensible way to do that is by the placement new, which will construct a new object, obtaining a new and valid value for p_, overwriting the old and useless memory content.
That said, you might think you could construct types for which repeated destructor was safe: for example, by setting p_ to 0 after the delete. That would probably work on most systems, but I'm pretty sure there's something in the Standard saying to invoke the destructor twice is UD regardless.