15

So in the following example, we cause class Foo to replace itself with *this = Foo(). I'm glad I just tested this because it turns out in this circumstance, the destructor of the old Foo doesn't get called. I guess that's because the default assignment operator just uses memcpy ... but as a language design question ... why wouldn't you make the default assignment operator destroy the assigned-to object first to prevent accidents?

http://codepad.org/9WCo6yZ5

#include <iostream>
using namespace std;

class MustBeDestroyed //(for some reason not shown here)
{
public:
  int i;
  MustBeDestroyed(int i) : i(i) {}
  ~MustBeDestroyed() { cout << "destroyed contained class " << i << endl; }
};

class Foo
{
public:
  MustBeDestroyed x;
  Foo(int y) : x(y) {}
  void replace_myself(int y) { Foo f(y); *this=f; }
  void print() { cout << "This is outer/inner class " << x.i << endl; }
  ~Foo() { cout << "destroyed outer class " << x.i << endl; }
};

int main()
{
  Foo a(1);
  a.print();
  a.replace_myself(2);
  a.print();
  return 0;
}
Sideshow Bob
  • 4,566
  • 5
  • 42
  • 79
  • 2
    What accidents? Assignment is just that - assigns a new value to an old value. – Luchian Grigore May 02 '13 at 14:47
  • 1
    The default assignment operator does not use memcpy (although a compiler optimization could result in that). It is a memberwise assignment. – huskerchad May 02 '13 at 14:48
  • 1
    `int i, j; i = 5; j = i;` are you saying that it is sensible to expect that I can't use `i` anymore? I disagree. – Fiktik May 02 '13 at 14:51
  • 2
    Five downvotes for a reasonably worded question with code example? The hate is strong today! -> suicide booth ;-P – Sideshow Bob May 02 '13 at 15:52

2 Answers2

7

Because destroying the object first would end the lifetime. Then you would have to invoke a constructor to start the new object's lifetime. But the behavior of operator= isn't to destroy the current object and create another, but to assign a new value to the existing object.

Basically, you violated the rule of 3.

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
2

Why would assignment call the destructor? It does exactly what is says it does: It calls the assignment operator. The compiler generated assignment operator simply does the obvious: assignment of all members from the old obejct to the new (using their assignment operation). Nothing more, nothing less. This is exactly the reason for the famous rule of three.

Now as to why it doesn't call the destructor: That would end the lifetime of the object. While it is theoretically possibly to construct a new object inplace of the old one, that approach is typically incorrect in the face of exception (look at this question for more about that), so it can't be used in the general case. Besides if it did the approach you proposed, it wouldn't call the assignment operators for the members, but destructor/copy constructor instead. That means that custom assignment behaviour (which doesn't actually need to be the same as copy behaviour) would not be honored.

Community
  • 1
  • 1
Grizzly
  • 19,595
  • 4
  • 60
  • 78
  • 2
    Assignment would call the destructor first to avoid a memory leak if the value being overwritten contained a ptr to data off the heap. If you simply overwrite the ptr, then you leak memory. Thus the built-in assignment operator should be overridden in this case (since the built-in will leak). – wcochran Feb 09 '16 at 04:44
  • Exactly, I once saw that one of the first implementations of `std::vector` actually called the destructor and later placement new. I think this is inefficient (pessimistic), doesn't have the strong-exception-guarantee and it looks just wrong. Of course we learned to write better C++ from those days. – alfC Feb 13 '19 at 08:03