C ++堆栈分配的对象分配和析构函数调用

时间:2017-05-07 17:17:07

标签: 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数据)
  • Foo析构函数调用0x ... 18(带有f2数据)

实际发生的事情:

  • 0x ... 58在堆栈上创建/初始化
  • 0x ... 18在堆栈上创建/初始化
  • 来自0x ... 18(f2)的
  • 数据被复制到0x ... 58
  • Foo析构函数调用0x ... 18(带有f2数据)
  • Foo析构函数调用0x ... 58(也使用f2数据)

所以最后, Foo析构函数被调用两次以获得相同的数据(f2)。很明显,我错过了一些关于内部如何运作的信息,那么有人可以指出我正确的方向吗?

2 个答案:

答案 0 :(得分:4)

您的实例 f 被分配了一个副本的Foo {&#34; f2&#34;},它不是新< / em>建设。

添加以下 operator = 覆盖以说明实际发生的情况。

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

答案 1 :(得分:3)

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

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

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

此赋值不会破坏f中以前存在的对象,它只会将数据成员复制到其中。由于Foo对象只有一个数据成员m_name,因此赋值只是将第二个对象的m_name复制到第一个对象中。

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

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