2017-05-07 38 views
3

我试图了解什么似乎是一个怪异的行为时分配一个新的值分配到堆栈上的对象(析构函数被调用两次相同的数据集)。我就开始与代码片段,其输出:C++堆栈分配的对象分配和析构函数调用

class Foo { 
    public: 
     Foo(const string& name) : m_name(name) { 
      log("constructor"); 
     } 
     ~Foo() { 
      log("destructor"); 
     } 
     void hello() { 
      log("hello"); 
     } 
    private: 
     string m_name; 
     void log(const string& msg) { 
      cout << "Foo." << this << " [" << m_name << "] " << msg << endl; 
     } 
    }; 

    int main() { 

     { 
      Foo f {"f1"}; 
      f.hello(); 

      f = Foo {"f2"}; 
      f.hello(); 
     } 
     cout << "scope end" << endl; 
    } 

输出:

Foo.0x7fff58c66a58 [f1] constructor 
    Foo.0x7fff58c66a58 [f1] hello 
    Foo.0x7fff58c66a18 [f2] constructor 
    Foo.0x7fff58c66a18 [f2] destructor 
    Foo.0x7fff58c66a58 [f2] hello 
    Foo.0x7fff58c66a58 [f2] destructor 
    scope end 

我希望发生:

  • 0X ...... 58被创建/初始化在堆栈上
  • 0x ... 18在堆栈上创建/初始化
  • Foo析构函数在0x ... 58上调用F1数据)
  • 富析构函数被调用于0X ... 18(具有f数据)

居然会发生什么:

  • 0X ...... 58时生成/初始化堆栈
  • 0X ... 18获取创建/初始化堆栈上从0X ... 18(F2)
  • 数据被复制到0X ... 58
  • 富析构函数被调用于0X ... 18(具有f数据)
  • 富析构函数被调用的0X ... 58(也具有f数据)

所以在最后,Foo析构函数被两次调用相同的数据(f2)。很明显,我错过了一些关于内部工作原理的东西,所以有人可以请我指出正确的方向吗?

+3

因为您已经复制了一个临时对象,它将'f'所保持的名称从''f1''更改为''f2''',所以不会看到“f1”'析构函数的消息。因此,你首先会看到临时的“f2”破坏,然后原始实例(现在称为“f2”)被破坏。请注意,数据不一样;它是具有相同值的副本。 –

+2

如果你的类有一个析构函数,它应该几乎肯定也有一个拷贝构造函数和赋值运算符。 –

+0

并且(可能)移动构造函数和移动赋值操作符(“五个规则”)。 –

回答

4

您的实例˚F被分配富{“F2”}的副本,这不是一个新的建设

添加以下运算符=重写以说明实际发生的情况。

Foo& Foo::operator=(const Foo& other) { 
    cout << "Foo::operator=(const Foo& other)" << endl; 
    m_name = other.m_name; 
    return *this; 
} 
3

之前创建第二Foo对象,你只需要在地址0x..58一个对象。

Address: 0x..58   Data: { m_name "f1" } 
Address: 0x..18   Data: unknown 

线f = Foo {"f2"};首先创建在地址0x..18一个新的Foo对象,其m_name值为"f2",并将其存储。然后它将该对象分配给变量f

此分配不会破坏f中先前存在的对象,它只会将数据成员复制到其中。由于Foo对象只有一个数据成员m_name,因此该作业仅将第二个对象的m_name复制到第一个对象中。

Address: 0x..58   Data: { m_name "f2" } 
Address: 0x..18   Data: { m_name "f2" } 

然后为每个这些对象调用析构函数。输出并不意味着同一个对象被销毁两次,它只是意味着两个对象都有相同的m_name