What would make a field variable become obsolete before entering the destructor upon deletion of the object?
I was a looking for an answer for this problem I'm having on this site and came across this:
Lifetime of object is over before destructor is called?
Something doesn't add up at all: if I've declared a pointer to SomeClass inside another WrapperClass, when I construct the WrapperClass I need to create a new SomeClass and delete it on destruction of the wrapper.
That makes sense and has worked so far.
The pointer is still valid and correct well into the destructor otherwise obviously I wouldn't be able to delete it.
Now my problem is that my field members (both an int and a pointer to a SomeClass array) of WrapperClass are garbage when I call the destructor. I've checked the wrapper object just after construction and the data is fine. The wrapper is actually a pointer in another Main class and the problem occurs when I destruct that Main (which destructs the wrapper) but works fine if I just delete the wrapper from another method in Main.
My paranoia led me to the above mentioned answer and now I'm totally confused.
Anybody care to shed some light on what's really going on here?
EDIT:
Node is the SomeClass.
class WrapperException{};
class Wrapper {
private:
struct Node { /*....*/ };
int numNodes;
Node** nodes;
public:
Wrapper() : numNodes(0) { nodes = new Node*[SIZE]; }
Wrapper(const Wrapper& other) { throw WrapperException(); }
Wrapper& operator=(const Wrapper& other) { throw WrapperException(); }
~Wrapper() { //calling delete Main gets me here with garbage for numNodes and nodes
for(int i = 0; i < numNodes; i++)
delete nodes[i];
delete nodes;
}
};
class MainException{};
class Main {
public:
Main() { wrapper = new Wrapper(); }
Main(const Main& other) { throw MainException(); }
Main& operator=(const Main& other) { throw MainException(); }
~Main() { delete wrapper; }
private:
Wrapper* wrapper;
};
You need to use the Standard library to implement this behaviour.
class Wrapper {
private:
struct Node { /*....*/ };
int numNodes;
std::vector<std::unique_ptr<Node>> nodes;
public:
Wrapper() : numNodes(0) { nodes.resize(SIZE); }
// No explicit destructor required
// Correct copy semantics also implemented automatically
};
class Main {
public:
Main() : wrapper(new Wrapper()) {}
// Again, no explicit destructor required
// Copying banned for move-only class, so compiler tells you
// if you try to copy it when you can't.
private:
std::unique_ptr<Wrapper> wrapper;
};
This code is guaranteed to execute correctly. When in C++, if you have used new[], delete or delete[], then immediately refactor your code to remove them, and review three times any use of non-placement new- constructing a unique_ptr is pretty much the only valid case. This is nothing but a common, expected outcome of manual memory management.
Since Grizzly isn't answering, I'll put this out there.
Both your Main class and your Wrapper class need properly implemented copy constructors and assignment operators. See The Rule of 3.
The problem is, if your class ever gets copied(which is easy to happen without you even realizing it), then the pointers get copied. Now you've got two objects pointing to the same place. When one of them goes out of scope, it's destructor gets called, which calls delete on that pointer, and the pointed to object gets destroyed. Then the other object is left with a dangling pointer. When it gets destroyed, it tries to call delete again on that pointer.
The lifetime of your wrapper object has ended, but the integer and pointer sub-objects as well as the pointee are still alive. When you invoke delete on the pointer, the pointee's lifetime ends, but the pointer still remains alive. The pointer's lifetime ends after your dtor is complete.
Thus, if your members have become corrupted, there is something else afoot.
Node** nodes;
should be
Node * nodes;
Also the destructor is wrong. It should be:
for(int i = 0; i < numNodes; i++)
delete nodes[i];
delete [] nodes;
There might be other problems as well as e.g. you haven't created a copy constructor or assignment operator so that might make it so that the copy of an object then deletes the object for you.
EDIT: changed the destructor...
Related
I am designing a custom C++ template container like this:
template <class C>
class Container {
public:
...
void clear() {
// should I call destructor on elements here?
for (i...)
array[i].~C(); // ?
}
~Container() {
delete [] array_;
}
private:
C* array_;
};
Should I call the destructor on elements manually inside clear()? If I don't, they will be called later when the container is destroyed (since I delete [] array_ in destructor), but this is not the expected behaviour (we expect them to be destroyed right inside clear(), just like std::vector does).
However, if I do call the destructors, that memory remains in place and when I will be adding new elements on top of the old ones (which now are destroyed), the assignment operator will be called on those destroyed elements, and this may result in undefined behavior.
Suppose I have a class:
class Foo {
public:
Foo() { foo_ = new int; }
~Foo() { delete foo_; } // note I don't explicitly set foo_ to nullptr here
Foo(Foo &&f) {
f.foo_ = std::exchange(foo_, f.foo_); // standard practice in move constructors
}
};
OK, this may look good so far, but now if I make a
Container<Foo> c;
c.add(Foo());
c.clear();
c.add(Foo());
when calling clear() the destructor of the initial Foo is called, leaving its foo_ pointer dangling. Next, when adding the second Foo, the temporary R-value is exchanged with the old contents of the destructed object and when the temp will be destroyed, its destructor will try to delete the same dangling pointer again, which will crash.
So, how to correctly clear() a container without leaving room for double deletion?
I also read that its recommended not to set pointers to nullptr in destructor in order not to not hide potential dangling pointer problems.
I'm a little confused about how to approach this.
EDIT:-------------------
There seems to be no compromise-free approach for a template container.
So far I see these options, as others pointed out:
completely delete the underlying array in clear(); this would be
safe but not performant. I cannot use this option however since I'm
implementing a lock-free multi-threaded container.
instead of calling the destructor on elements in clear(), I would call the default constructor instead: array[i] = C(); This seems
like the best solution so far - except it still implies an extra
default construction.
use placement new in add() - this seems to work for copy-construction. However, move-construction into an uninitialized object still seems problematic because most move constructors are implemented with exchanges between pointers - this would leave the source object (moved from) invalid.
The delete [] array_ will invoke the destructor for each element of array_ (assuming C is a type with a destructor).
Invoking a destructor twice on any given object gives undefined behaviour.
This means your clear() member function should not directly invoke destructors for the array elements.
If you insist on having a separate clear() function, which does not interfere with working of the destructor, simply implement it as
void clear()
{
delete [] array_;
array = nullptr; // NULL or 0 before C++11
}
This won't interfere with the destructor since operator delete has no effect if acting on a NULL pointer.
As you specified in the comments, in the unassigned cells you have objects constructed by the default constructor (T()). That may be bad for performance, but certainly preserves the object abstraction.
Instead of deleting the entries, just replace them with the ones constructed by the default constructor:
template <class C>
class Container {
public:
...
void clear() {
for (i...)
array_[i] = C();
}
~Container() {
delete [] array_;
}
private:
C* array_;
};
Alternative implementation
On the other hand, I would propose a more performant approach, although it breaks the nice C++ abstraction. You could allocate the memory without invoking the unnecessary default constructor:
template <class C>
class Container {
public:
Container(int n) {
array_ = (C*)malloc(sizeof(C)*n);
size_ = 0;
}
...
void clear() {
for (... i < size_ ...)
array_[i].~C();
size_ = 0;
}
~Container() {
clear();
free(array_);
}
private:
C* array_;
int size_;
};
Here you do call destructors on all the initialized elements, but you do not call it second time, because you keep track of which are initialized, which are not.
According to definition : When an object of this class is copied, the pointer member is copied, but not the pointed buffer, resulting in two objects pointing to the same so we use copy constructor. But in following class there is no copy constructor but it Works! why? Why i dont need to deep copying?
class Human
{
private:
int* aValue;
public:
Human(int* param)
{
aValue=param;
}
void ShowInfos()
{
cout<<"Human's info:"<<*aValue<<endl;
}
};
void JustAFunction(Human m)
{
m.ShowInfos();
}
int main()
{
int age = 10;
Human aHuman(&age);
aHuman.ShowInfos();
JustAFunction(aHuman);
return 0;
}
output:
Human's info : 10
Human's info : 10
A copy constructor is useful when your class owns resources. In your case, it doesn't - it neither creates nor deletes aValue itself.
If you did do that though, say:
Human()
{
aValue=new int;
}
and properly cleaned up the memory:
~Human()
{
delete aValue;
}
then you'd run into issues, because Human a; and Human b(a); would have the members aValue point to the same location, and the when they go out of scope, the same memory is released, resulting in a double delete.
As has already been mentioned, the reason it works for you is that it's actually fine to have multiple pointers pointing to the same object - that's kind of the point, share data without copying it.
the issues arrive if the object pointed to has it's lifetime managed by the wrapping class, ie: it is created and destroyed within methods implemented by the class - typically the class's constructor and destructor. In that case a deep copy would be necessary in the copy constructor.
In your (admittedly contrived) example where the int has a longer lifetime that the object carrying the pointer you should examine using a reference as a member, initialised in an initialiser list. This removes the possibility of forgetting yourself and deleting the object from within the class.
class Human
{
private:
int& aRef;
public:
Human(int& param)
: aRef(param)
{
}
};
You should also consider whether the pointer or reference should be to a const object:
class Human
{
private:
const int& aRef;
public:
Human(const int& param)
: aRef(param)
{
}
};
This works because the pointer in the class points to the stack variable age.
You haven't written a destructor for your class Human, so doesn't try to do a double delete when the Human is copied in JustAFunction
If you used it differently, for example sending a newed int into the class you would have a memory leak instead.
Human human(new int);
If you copy that, you have two pointers pointing to the same memory, which in itself isn't a problem, but makes it hard to decide who is in charge of releasing that memory.
I have recently had some errors (bad_alloc) due to my lack of a destructor.
I currently have two classes, set up in this way:
class ObjOne {
friend class ObjTwo;
public: //constructors and some other random methods
ObjOne(int n) {
}
ObjOne() {
}
private:
int currSize;
int size;
int *jon;
};
class ObjTwo {
public: //constructors and some other methods
ObjTwo(ObjOne, int n) {} //
ObjTwo() {}
ObjTwo(const ObjTwo &source) { //copy constructor
num = source.num;
x = source.x;
myObjOne=source.myObjOne;
}
~ObjTwo() { //destructor
delete #
delete &x;
delete &myObjOne;
}
private:
ObjOne myObjOne;
int num, x;
};
and here is my operator= for ObjTwo
ObjTwo& ObjTwo::operator=(const ObjTwo& other) {
num = source.num;
x = source.x;
myObjOne=source.myObjOne;
return *this;
}
Firstly, my assumptions were (Please correct these if it is incorrect):
ObjOne does NOT need a destructor, as it is only primitive types, and when the compiler will use the default destructor to clean it up.
ObjTwo DOES need a destructor, as it contains ObjOne
ObjTwo Destructor will need to deallocate memory from x,num and myObjOne.
I have made a few attempts at destructors with this, however I still run into bad_alloc errors (when testing with huge loops etc.) or other errors (with the current one it just crashes when destructor is called).
Any guidance on what I am doing wrong is appreciated
EDIT:
I have a bad_alloc exception being thrown when I simply put this in a loop:
ObjTwo b(//some parameters);
ObjTwo a(//some parameters);
for (int i=0; i<20000000; i+) {
bool x = (a == b);
}
and this is overloaded == operator
bool ObjTwo::operator==(const ObjTwo& other) {
ObjTwo temp = other;
for(int i=myObjOne.x; i>=0; i--) {
if(myObjOne.get(i)!=temp.myObjOne.get(i)) {
return false;
}
}
return true;
}
After some reading on the error it seemed that it was caused to due running out of memory; which my unfunctioning destructor would cause. What could be the problem here?
and the get method simply returns jon[i];
You do not need any of your uses of delete. You should only delete something that you have previously allocated with new.
In ObjTwo, the members myObjOne, num, and x definitely should not be deleted. In fact, you should never take the address of a member and delete it. Members are destroyed automatically when the object they are a member of is destroyed.
Consider, for example, having a member which was defined like this:
int* p;
This p is a pointer to int. The pointer itself will be destroyed when the object it is part of is destroyed. However, imagine that in the constructor you dynamically allocate an int object like so:
p = new int();
Now, because new dynamically allocate objects, you will need to delete the object pointed to by p. You should do this in the destructor with delete p;. Note that this isn't destroying p, it's destroying the object it points out. Since p is a member, you should not destroy it manually.
ObjOne MIGHT need a destructor. This is not about primitive types, but about things like dynamically allocated memory (pointers). You have an int* member, which might be allocated dynamically or at least be a pointer to dynamic memory. So you will need to use delete or delete[] on this one.
What you are doing in ~ObjectTwo is fatal! You are trying to delete memory from the stack -> undefined behavior but will mostly crash. All of your objects/variables are stack-allocated, so you must not delete them...
I have a class that I want to contain multiple objects of something I created. Right now the code that works is:
process.h:
private:
myObj *data;
process.cc:
data = new myObj[10];
I would like to pass a value to the constructor however, so I tried to convert it to a std::vector (after modifying constructor to take a value).
process.h:
private:
std::vector<myObj> data;
process.cc:
for (int m=0; m<10; m++) data.push_back( myObj(1.2) );
When I try that it crashes upon execution with
*** glibc detected *** ... corrupted double-linked list: ... ***
And the backtrace in gdb shows an error in the destructor when I tried to free some memory for other arrays I allocated. A search didn't show up anything that was obvious. I am using a few static member variables in myObj, could that be an issue?
You are experiencing a double deletion bug. Consider this simple example:
struct Other {};
struct MyObj {
Other *p;
MyObj () : p(new Other) {}
~MyObj () { delete p; }
};
std::vector<MyObj> data;
data.push_back(MyObj());
The temporary object that is pushed onto data is stored properly. However, since it is a temporary, it is destroyed right after the push. This means, the p member is deleted when the temporary is destroyed, so the vector's version of the copy has a dangling pointer. When the vector object is destroyed, the pointer will be deleted again, resulting in a corrupted heap. The error message you received was from the glibc code complaining about the resulting bad state.
To fix this problem, a proper copy constructor should be defined, to pass ownership of the objects from the temporary to the destination. The rule of three says we should define the assignment operator as well.
struct MyObj {
mutable Other *p;
MyObj () : p(new Other) {}
MyObj (const MyObj &o) : p(o.p) { o.p = 0; }
~MyObj () { delete p; }
const MyObj & operator = (MyObj o) {
using namespace std;
swap(*this, o);
return *this;
}
};
The use of mutable is required to be able to modify the p member when the instance is const, and const was needed because temporaries are being passed in to the copy constructor. With this change, pushing items into the vector work fine.
A better solution would be to define p to use a unique_ptr instead.
struct MyObj {
std::unique_ptr<Other> p;
MyObj () : p(new Other) {}
};
No destructor is needed in this example, since the default destructor will destruct p, which will cause the Other instance to be deleted by unique_ptr.
You're trying to use a vector to store multiple objects within a class? I have run into this problem also and the only way I could fix this was to place the function you are using the vector in, in the header. What I believe is happening is you're providing the vector with a type, in this case, myObj, but the .cpp can not see what type you've defined the vector as. So sticking the function inside the Header seems to fix it. I believe there are other ways around this but I've not looked into the problem much.
example code:
class A
{
private:
vector<myObj> data;
public:
A();
~A();
printData()
{
for(int i = 0; i < data.size(); i++)
{
printf("X position: %.2f Y position: %.2f Z position: %.2f \n", data.at(i).x, data.at(i).y, data.at(i).z);
}
};
}
This may be the problem, or, it is your naming convention. I am not sure what you are doing but how does data *myObj; and data = new myObj[10]; actually work? Wouldn't it be myObj = new data[10]? If so then your vector would be:
vector<data> myObj;
Sorry about the title. I wasnt sure what to name it. If any mods are reading and they understand the question then please rename if needed too.
Say you create a new variable (varOne).
Inside the varOne code, other variables are created as new (varTwo, varThree).
If you call delete on varOne, will varTwo and varThree be deleted, or do you need to delete them AND delete varOne?
You only need to delete varTwo and varThree, because when you fall out of varOne's destructor, the delete you used to invoke varOne's destructor will clean up that instance of varOne.
In other words, in the example below, varOne is Foo, varTwo is m_i, and varThre is m_c:
class Foo
{
public:
Foo() : m_i( new int ), m_c( new char ) { }
~Foo() { delete m_i; delete m_c; }
// don't forget to take care of copy constructor and assignment operator here!!!
private:
int* m_i;
char* m_char;
};
main()
{
Foo* p = new Foo;
delete p;
}
Also make sure that when you do this, you follow The Rule of Three or your program will suffer memory problems. (In other words, if you are doing memory allocation in your constructor, be sure you either override or delete the default copy-constructor and assignment operators).
You have to delete them and delete varOne seperately, but actually the constructor of varOne should allocate those variables and the destructor should deallocate them if they have to be on the heap for some reason. It would be better to just store them by value and be rid of new and delete for good.
I'm not 100% sure what you mean, but in general, anything that you allocate with new, you have to individually deallocate with delete.
If you mean this in the context of a C++ class, you will need to manually delete varOne and varTwo of the destructor.
Use a smart pointer, and never ever ever delete anything in your own code.
I'm not sure how to understand your question, since you don't new a variable (all variables are static, automatic or member variables) but objects (the pointers you get from new will however usually assigned to use used to initialize variables, maybe that's what you meant?). Therefore I'll give a general answer ad hope that what you asked for is included.
First, as a basic rule, every object you allocate with new has to be deallocated explicitly with delete. However, the delete might be hidden in another object, like shared_ptr and scoped_ptr/unique_ptr from boost or C++11, or auto_ptr in earler versions of C++.
If your object contains subobjects, it's usually best to make them direct members, so you don't allocate them with new at all (indeed, that's a general rule in C++: If you don't absolutely have to dynamically allocate, don't). That is, you'd write your class as
class X
{
public:
// ...
private:
Type1 subobject1;
Type2 subobject2:
};
and don't have to mess with new/delete for the sub objects at all. However if you need to dynamically allocate the objects, you also have to delete them, e.g.
class X
{
public:
X()
{
subobject1 = new Type1();
try
{
subobject2 = new Type2();
}
catch(...)
{
delete subobject1;
}
}
~X()
{
delete subobject2;
delete subobject1;
}
// ...
private:
X(X const&); // disabled
X& operator=(X const&); // disabled
Type1* subobject1;
Type2* subobject2;
};
Note the rather complicated code in X's constructor to make sure the object is correctly cleaned up even in case of an exception. Also note that you also have to implement copy construction and assignment or disable them by making them private and unimplemented (note that C++11 offers the special syntax = delete to disable them). You can save yourself a lot of the trouble by using a smart pointer (but you still have to take care about copy construction and assignment, at least with the usual smart pointers):
class X
{
public:
X():
subobject1(new Type1()),
subobject2(new Type2())
{
}
private:
X(X const&) = delete; // disabled
X& operator=(X const&) = delete; // disabled
std::unique_ptr<Type1> subobject1;
std::unique_ptr<Type2> subobject2;
};
Here I've used C++11's unique_ptr (and consequently also used C++11 syntax for removing copy constructor and assignment operator). Note that on first impression this code seems to have no delete at all; however those deletes are actually hidden in the destructor of unique_ptr. Also note that now the explicit exception handling in the constructor is no longer needed; since the deleting is done in the destructors of the unique_ptrs, C++'s exception handling rules for constructors automatically take care of this.