为什么没有为匿名对象调用析构函数

Why destructor is not getting called for anonymous objects?

本文关键字:对象 调用 析构函数 为什么      更新时间:2023-10-16

在工作时,我遇到了一段奇怪/令人困惑的代码,我觉得它与匿名对象生命周期概念有关。以下是代码示例:

#include<iostream>
#include<string>
class A {
private:
    int i;
    std::string s;
public:
    A(int ii, std::string ss = "Hello") { i = ii; s = ss; }
    void Display() { std::cout<<i<<"n"; }
    ~A() { std::cout<<"A::~A()"<<"n";}
};
void function()
{
    A a = 1;
    //A a = A(1);
    a.Display();
}
int main()
{
    function();
    return 0;
}

VS2010中的输出1(如果A A=1)

 1
  A::~A()

VS2010中的输出2(如果A A=A(1))

A::~A()
1
A::~A()

output2完全有意义,因为析构函数被调用两次(包括匿名对象)。

然而,output1让我感到困惑,无法理解为什么析构函数只被调用一次(不用于匿名)对象。

A a = 1;

上面的行将调用类A的复制构造函数(A(const A& rhs)),并且编译器应该使用参数1为其创建匿名对象。如果是这种情况,析构函数应该被调用两次。

有人能向我解释一下这种行为吗?。可能是我错过了一些显而易见的东西。

A a = A(1);等效于A a = 1;。然而,在这两种情况下,都可能出现复制省略:A(1)实际上是直接构建到a中的,而不是单独构建然后复制或移动。

由编译器决定是否在任何允许的场景中执行副本省略(如上面的链接所述)。

编译器正在为A a = 1消除副本,但不为A a = A(1);消除副本,gcc在这两种情况下都可以消除副本,这可以用-fno-elide-constructors进行测试。