15

所以在下面的例子中,我们让 classFoo*this = Foo(). 我很高兴我刚刚测试了这个,因为在这种情况下,旧的析构函数Foo不会被调用。我猜那是因为默认赋值运算符只是使用memcpy......但作为一个语言设计问题......你为什么不让默认赋值运算符首先破坏分配对象以防止意外?

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;
}
4

2 回答 2

7

因为首先销毁对象会结束生命周期。然后你必须调用一个构造函数来开始新对象的生命周期。但是 operator= 的行为不是销毁当前对象并创建另一个对象,而是为现有对象分配一个新值。

基本上,你违反了 3 的规则。

于 2013-05-02T14:48:37.320 回答
2

为什么赋值会调用析构函数?它完全按照它所说的去做:它调用赋值运算符。编译器生成的赋值运算符只是做了显而易见的事情:将所有成员从旧对象赋值给新对象(使用它们的赋值操作)。不多也不少。这正是著名的三法则的原因。

现在至于为什么它不调用析构函数:那将结束对象的生命周期。虽然理论上可以构造一个新对象来代替旧对象,但这种方法在面对异常时通常是不正确的(请查看这个问题以了解更多信息),因此它不能在一般情况下使用。此外,如果它采用您提出的方法,它不会调用成员的赋值运算符,而是调用析构函数/复制构造函数。这意味着不会尊重自定义分配行为(实际上不需要与复制行为相同)。

于 2013-05-02T14:50:30.773 回答