I’m having a memory-related crash in my project. I managed to reduce it down to the following “toy” project:
class Foo {
public:
Foo() : bar(nullptr) {
bar = new int(3);
}
~Foo() {
if (bar) {
delete bar;
bar = nullptr;
}
}
private:
int* bar;
};
Foo test() {
Foo foo;
return foo;
}
int main() {
test();
// <--- Crash!
return 0;
}
I cannot figure out why I’m crashing at the line specified. This is what I’ve gathered so far, please do correct me if I’m wrong:
Basically, I’m creating foo on the stack in test(). Foo allocates some memory on the heap. All is well. Then I try to return foo. foo is returned, but it is immediately destroyed. Then, when exiting, I’m again trying to destroy foo; and hence I’m calling Foo‘s destructor twice, and I crash. What I do not get is why this is a problem. I’m checking for Foo::bar being null before deleting it, and if I do delete it, I set it to null afterwards.
Why should this cause a crash? How can I “fix” this? What am I doing wrong? I’m so confused! 🙁
Update: The main reason for why this is happening is because of lack of a copy constructor, as stated in the answers below. However, my original project did have copy constructor, or so I thought. Turns out if your class is derived, you must explicitly create a copy constructor for the derived class. Base(const Derived& other) does not count as a copy constructor!
You violated the rule of three.
When you’re manually managing memory inside your constructor and destructor, you MUST also provide a copy constructor and assignment operator, otherwise your program will double-delete and use memory after delete.
In your particular example, you have the compiler-provided copy constructor. When
foois copied to the return value oftest, you have two objects with the samebarpointer. The localfoogoes out of scope and is destroyed, then itsbaris set tonullptr. But the copy, the return value, still has a non-null pointer. Then it is destroyed also, and deletes the same memory again.