为什么不调用析构函数?

Why destructor is not called?

我写了两个程序来理解复制对象的概念。 第一个:

#include<bits/stdc++.h>
using namespace std;

class myInt
{
    int x;
public:
    myInt()
    {
        cout<< "default constructor is called" << endl;
    }
    myInt(int x)
    {
        cout<< "constructor is called with initializer" << endl;
        this->x = x;
    }
    ~myInt()
    {
        cout<< "destructor is called" << endl;
    }
};

myInt func(myInt ob)
{
    return ob;
}

int main()
{
    myInt ob1(2);
    func(ob1);
}

输出:

constructor is called with initializer
destructor is called
destructor is called
destructor is called

这里的析构函数被调用了3次,也就是说创建了3个对象。一个用于对象 'ob1',一个用于 func() 内部的 'ob',另一个用于从 func() 返回 'ob'。 我的第二个代码:

#include<bits/stdc++.h>
using namespace std;

class myInt
{
    int x;
public:
    myInt()
    {
        cout<< "default constructor is called" << endl;
    }
    myInt(int x)
    {
        cout<< "constructor is called with initializer" << endl;
        this->x = x;
    }
    ~myInt()
    {
        cout<< "destructor is called" << endl;
    }
};

myInt func(myInt ob)
{
    return ob;
}

int main()
{
    myInt ob1(2);
    myInt ob2 = func(ob1);
}

输出:

constructor is called with initializer
destructor is called
destructor is called
destructor is called

这里也创建了 3 个对象作为第一个对象。但是,当我将 func() 返回的对象存储在其中时,不应该再调用一个 'ob2' 的析构函数吗?为什么两种情况下的析构函数调用次数相同?

正如评论中指出的那样,由于复制省略,当它们仅用于初始化另一个对象时,创建临时对象可能会被省略。使用 -fno-elide-constructors 编译您的代码以将其关闭,您将阅读 destructor is called 四次。这里有一个demo.

然而,在 c++17 中情况有所不同。它保证在某些情况下省略副本(prvalue 用作具有相同类型的对象的初始值设定项)。在那里,它不再被视为优化(即 -fno-elide-constructors 在这里没有效果)。看到这个不错的 article or the proposal for details. The following example(从链接文章中窃取)可以用 c++17 很好地编译,因为我们保证没有 copy-/move 构造函数被调用:

struct Foo {
  Foo() { std::cout << "Constructed" << std::endl; }
  Foo(const Foo &) = delete;
  Foo(const Foo &&) = delete;
  ~Foo() { std::cout << "Destructed" << std::endl; }
};

Foo f() {
  return Foo();
}

int main() {
  Foo foo = f();
}