为什么析构函数被调用两次?

时间:2014-01-18 19:28:45

标签: c++ operator-overloading type-conversion

#include <iostream>
using namespace std;

class A 
{
public:
    A() { cout << "A's constructor" << endl; }
    ~A() { cout << "A's destructor" << endl; }
}; 

class B
{
public:
    operator A() const { return A(); }
};

void f(A q) {}

int main() 
{
    B d1;  
    f(d1); 
    return 0;
} 

这是我在运行代码之前要做的事情: 对f的调用导致调用B类中的转换器函数,该函数返回一个临时对象。 q的构造函数被调用,当f退出时,q的析构函数被调用。我期待以下输出:

A的构造函数
A的析构函数

但我得到的输出是:

A的构造函数
A的析构函数
A的析构函数

由于还有另一个析构函数,因此必须在某处创建一个额外的对象。有人能解释一下这里发生了什么吗?

4 个答案:

答案 0 :(得分:1)

将此作为您的班级A:

class A 
{
public:
    A() { cout << "A's constructor: " << this << endl; }
    A(const A& a) { cout << "A's copy constructor: " <<this << " form " << &a << endl; }
    A(A&& a) { cout << "A's move constructor: " <<this << " form " << &a   << endl; }
    A& operator=(const A& a) { cout << "A's assignment" <<this << " form " << &a  << endl; }
    ~A() { cout << "A's destructor: "<< this << endl; }
}; 

你会明白为什么。

答案 1 :(得分:0)

这里有3个A个对象的可能性。首先是转换运算符中A()创建的临时对象。然后,由于转换运算符的返回类型为A,因此将临时值复制到返回值中。然后,转化的返回值将复制到q的参数f

要复制对象,将调用复制构造函数。不会调用默认构造函数,因此您不会看到正在打印的“A的构造函数”消息。

恰好,编译器忽略了这些副本中的一个,因此实际上只有一个副本出现。哪一个被省略,我不能告诉你(但它可能是复制到返回值)。

答案 2 :(得分:0)

我认为第一个析构函数调用临时对象,而第二个析构函数是由移动语义构造的对象。

答案 3 :(得分:0)

之前已经多次询问过这个问题,但由于它如此通用,很难找到较旧的帖子。

您正在通过值传递周围的对象,这意味着副本由复制构造函数创建。复制构造函数是在您的情况下创建“额外对象”的原因。同时,您不会从复制构造函数中输出任何内容,因此看不到调用。

您还必须向复制构造函数添加调试输出。这样你就会看到实际构造的内容和时间。