【问题标题】:Why is my destructor called twice?为什么我的析构函数被调用了两次?
【发布时间】:2013-01-12 23:18:40
【问题描述】:

假设我有一个学生类的方法:

Student Student::method(Student x)
{
    //nothing important
    return x;
}

复制构造函数被调用两次,一次是当对象 x 作为参数发送时,第二次是从函数返回 x 时。

当我调用此方法时,为什么以及何时会调用 Student 类的析构函数两次? 调用是这样的:a = b.method(c),其中 a、b 和 c 是 Student 对象。

【问题讨论】:

  • 是构造函数还是析构函数的问题?标题说明一件事,问题主体说明另一件事。

标签: c++ destructor


【解决方案1】:

对于您的示例,a = b.method(c);,可能会发生三个副本,除了复制省略。第一种是将c 对象复制到函数参数x 时。第二个是从函数返回x 对象时。第三种是将返回值复制到a 对象中。前两个涉及拷贝构造函数,最后一个涉及拷贝赋值运算符,除非你把它改成Student a = b.method(c);,在这种情况下它们都使用拷贝构造函数。

abc 都将在其作用域结束时被销毁。对象x 将在method 函数结束时被销毁。函数的返回值将在包含它的完整表达式的末尾销毁 - 即,一旦 a = b.method(c); 完成。

但是,并非所有这些副本都必须发生 - 在某些情况下,允许编译器省略或省略类的复制/移动构造。将发生第一次复制到函数参数中。函数的第二个副本将被视为先移动,然后再尝试复制它。此复制或移动可能会被省略。如果您使用复制赋值,则从临时返回值到a 的最终复制将发生,但如果您使用复制构造函数(如Student a = b.method(c);),则可能会被省略。

【讨论】:

    【解决方案2】:

    如果构造了两个 Student 对象,则必须将它们销毁。传入参数和传出返回值的副本需要析构。

    【讨论】:

      【解决方案3】:

      x 的析构函数在函数返回时被调用(在x 被复制到返回值之后)。

      在包含函数调用的完整表达式的末尾调用返回值的析构函数(除非返回值通过分配给引用来延长其生命周期)。

      每个被构建的具有自动存储持续时间的对象都会被自动销毁(通常以相反的构建顺序)。您构造了两个对象(x 和返回值),因此有两个析构函数调用。

      【讨论】:

      • 那么在我将 b.method(c) 返回的对象分配给该对象的行之后,该对象被破坏了吗?这和=没有关系吧?
      • @Sorin:正确。在某些情况下允许“复制省略”变得棘手的唯一部分,例如Student a(b.method(c)); 可能(或可能不会,未指定)直接在a 对象中构造返回值,从而扩展返回值的生命周期。 Student const& a(b.method(c)); 也将(肯定)将返回值的生命周期延长到 a 引用的范围。
      猜你喜欢
      • 2015-07-26
      • 2021-11-06
      • 1970-01-01
      • 2013-11-24
      • 2020-02-23
      • 2011-02-07
      • 1970-01-01
      • 2013-12-11
      相关资源
      最近更新 更多