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 开发者_JAVA技巧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 foo
is copied to the return value of test
, you have two objects with the same bar
pointer. The local foo
goes out of scope and is destroyed, then its bar
is set to nullptr
. But the copy, the return value, still has a non-null pointer. Then it is destroyed also, and deletes the same memory again.
You need to implement a copy-constructor and, most likely, an assignment operator.
Really, though, your problem lies in manually managing memory. This is almost always a terrible idea, as it is one of the most common ways bugs creep into your code. Use shared_ptr
s instead of manually managing memory in your code, and it is amazing how much easier your code is to maintain!
精彩评论