返回使用braced init list初始化的对象时,我保证会有一对构造函数和析构函数调用吗?

aut*_*tec 4 c++ c++11

以下面的课程为例

#include <iostream>

using namespace std;

class A{
private:
    int a_;
    int b_;

    A(const A&) = delete;
    A& operator=(const A&) = delete;
    A(A&&) = delete;
    A& operator=(A&&) = delete;

public:
    A(int a, int b) : a_{a}, b_{b}{cout<<"constructed\n";}

    void ephemeral() const{cout<<"operation\n";}

    ~A(){cout<<"destructed\n";}

};

A make_A(int a, int b){
    return {a, b};
}

int main(){
    make_A(1, 2).ephemeral();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

它给出了预期的结果.

构造对象,执行操作,然后对其进行破坏.

但是,我担心这是否有保证.我主要担心的是,由于标准给予编译器的自由,我是否能看到任何我不知道的影响.

我不认为copy-elision是一个因素,因为所有的移动和复制构造函数都被声明删除,所以它们怎么能被调用?

被调用的唯一构造函数是带有两个整数的构造函数.我可以确定这在编译器,平台和优化级别上的表现是否一致?

我怀疑答案是肯定的,但可能会有微妙之处.

Yak*_*ont 5

当你return {a,b};直接构造返回值时.

不会创建临时的,逻辑的或其他的.不会出现任何缺陷.

此返回值在返回的上下文中可用main.你可以调用它的.ephemeral()操作.在完整表达式结束时,它超出了范围,除非您将它"存储"在A const&(引用生命周期扩展插入A&&)或(存储)中,或者存储在auto const&或者auto&&像这样的变量中:

auto&& a = make_A(1, 2);
a.ephemeral();
Run Code Online (Sandbox Code Playgroud)

但是,在上述情况下,不会发生复制.

这些操作都不会导致标准下的副本.

在某些情况下,您是正确的,可以省略复制构造.Elision是指两个物体的身份和生命时间合并在一起的时候.如果make_A阅读:

A make_A(int a, int b){
  A r{a,b};
  return r;
}
Run Code Online (Sandbox Code Playgroud)

r可以被省略为返回值.但是,在这里,编译器会要求A(A const&)或被A(A&&)定义,所以它不会用你的编译A.在实践中,一旦检查它们被定义,它就不会调用它们,因为r内部make_A将被省略为与返回值相同的对象make_A.

同样的,

A a = make_A(1,2);
Run Code Online (Sandbox Code Playgroud)

返回的临时值make_A被省略为与命名变量相同a.Elision是短暂的,所以这也可以将一个变量放在 一起make_A.在这种情况下,您还需要A(A&&)A(A const&)存在.

通过删除移动/复制ctors,它们无法被调用,因此无法复制对象.每个构造函数只能调用一个析构函数(禁止手动构建或销毁).

如果代码试图调用它们,它将在编译时生成错误.


在C++ 17中,您甚至return A(a,b);可以获得类似的保证.

您也可以A a = make_A(1,2);和类似的保证发生.

这被描述为"保证省略",而是将一些操作变成"如何构建某些东西的描述".

因此,在某些情况下,您可以在C++ 03或C++ 11或C++ 14中执行需要移动或复制ctors的操作,但在C++ 17中,现在执行与"elision"类似的操作更长时间需要移动或复制ctors.