When assigned in C ++, does the object that we assigned breaks down?

Is the next code fragment leaking? If not, then where are the two objects that are built in foobar () destroyed?

class B { int* mpI; public: B() { mpI = new int; } ~B() { delete mpI; } }; void foobar() { B b; b = B(); // causes construction b = B(); // causes construction } 
+4
source share
5 answers

The default copy assignment operator makes a copy by type.

So in your case:

 { B b; // default construction. b = B(); // temporary is default-contructed, allocating again // copy-assignment copies b.mpI = temp.mpI // b original pointer is lost, memory is leaked. // temporary is destroyed, calling dtor on temp, which also frees // b pointer, since they both pointed to the same place. // b now has an invalid pointer. b = B(); // same process as above // at end of scope, b dtor is called on a deleted pointer, chaos ensues. } 

See clause 11 in Effective C ++ 2nd Edition for details.

+7
source

Yes, this is a leak. The compiler automatically provides an additional method because you did not define it. The generated code is equivalent to this:

 B & B::operator=(const B & other) { mpI = other.mpI; return *this; } 

This means that the following occurs:

 B b; // b.mpI = heap_object_1 B temp1; // temporary object, temp1.mpI = heap_object_2 b = temp1; // b.mpI = temp1.mpI = heap_object_2; heap_object_1 is leaked; ~temp1(); // delete heap_object_2; b.mpI = temp1.mpI = invalid heap pointer! B temp2; // temporary object, temp1.mpI = heap_object_3 b = temp1; // b.mpI = temp2.mpI = heap_object_3; ~temp1(); // delete heap_object_3; b.mpI = temp2.mpI = invalid heap pointer! ~b(); // delete b.mpI; but b.mpI is invalid, UNDEFINED BEHAVIOR! 

This is obviously bad. This is likely to happen anyway if you break a rule of three . You have defined a non-trivial destructor as well as a copy constructor. However, you did not determine the purpose of the copy. Rule three is that if you define any of the above, you should always define all three.

Instead, follow these steps:

 class B { int* mpI; public: B() { mpI = new int; } B(const B & other){ mpI = new int; *mpi = *(other.mpI); } ~B() { delete mpI; } B & operator=(const B & other) { *mpI = *(other.mpI); return *this; } }; void foobar() { B b; b = B(); // causes construction b = B(); // causes construction } 
+4
source

You create three objects, and all of them will be destroyed. The problem is that the default assignment operator will execute a shallow copy. This means that the pointer is copied, which causes it to be deleted more than once. This causes undefined behavior.

This is the reason for the rule of 3 . You have a destructor, but not two others. You need to implement a copy constructor and a copy assignment operator, both of which must make a deep copy. This means highlighting a new int, copying the value.

 B(const B& other) : mpI(new int(*other.mpI)) { } B& operator = (const B &other) { if (this != &other) { int *temp = new int(*other.mpI); delete mpI; mpI = temp; } return *this; } 
+3
source

As indicated several times, you have violated rule three. Just to add to the links, there is a big discussion about this overflowing stack: What is the rule of three?

0
source

Just in order to offer a different approach to solving the problems of the code that I originally posted, I think I could keep the pointer in class B, but take memory management. Then I do not need a custom destructor, and therefore I do not break rule 3 ...

 class B { int* mpI; public: B() {} B(int* p) { mpI = p; } ~B() {} }; void foobar() { int* pI = new int; int* pJ = new int; B b; // causes construction b = B(pI); // causes construction b = B(pJ); // causes construction delete pI; delete pJ; } 
0
source

All Articles