C++ 删除了所有自动生成的构造函数/运算符的类仍然可以从函数返回吗?
最近,我遇到了这个描述如何初始化非默认可构造元素的C++ 删除了所有自动生成的构造函数/运算符的类仍然可以从函数返回吗?,c++,return-value,c++17,deleted-functions,C++,Return Value,C++17,Deleted Functions,最近,我遇到了这个描述如何初始化非默认可构造元素的std::array。我并不感到惊讶,因为这个答案显然不起任何作用 相反,它使用聚合初始化构造一个临时的std::array,然后在函数返回时移动(如果move构造函数可用)或复制到命名变量中。所以我们只需要move构造函数或copy构造函数就可以了 或者我是这么想的 然后出现了一段令我困惑的代码: struct foo { int x; foo(int x) : x(x) {} foo() = delete; f
std::array
。我并不感到惊讶,因为这个答案显然不起任何作用
相反,它使用聚合初始化构造一个临时的std::array
,然后在函数返回时移动(如果move构造函数可用)或复制到命名变量中。所以我们只需要move构造函数或copy构造函数就可以了
或者我是这么想的
然后出现了一段令我困惑的代码:
struct foo {
int x;
foo(int x) : x(x) {}
foo() = delete;
foo(const foo&) = delete;
foo& operator=(const foo&) = delete;
foo(foo&&) = delete;
foo& operator=(foo&&) = delete;
};
foo make_foo(int x) {
return foo(x);
}
int main() {
foo f = make_foo(1);
foo g(make_foo(2));
}
所有五个特殊成员构造函数/运算符都被显式删除,所以现在我不能从返回值构造对象,对吗
错。
令我惊讶的是,它是用gcc(使用C++17)编译的
为什么要编译?显然,要从函数
make_foo()
返回foo
,我们必须构造一个foo
。这意味着在main()
函数中,我们正在从返回的foo
分配或构造一个foo
。这怎么可能 欢迎来到的精彩世界(C++17新增。另请参见)
在所有这些情况下,您都是从类型为foo
的prvalue初始化foo
,因此我们只需忽略所有中间对象,直接从实际的初始值设定项初始化最外层的对象。这完全等同于:
foo f(1);
foo g(2);
我们甚至不考虑移动构造函数在这里——所以它们被删除的事实并不重要。具体的规则是,只有在这一点之后,我们才考虑构造函数并执行重载解析。注意,在C++复制17之前(确保复制拷贝之前),您可能已经返回具有支撑的init列表的对象:
foo make_foo(int x) {
return {x}; // Require non explicit foo(int).
// Doesn't copy/move.
}
但用法会有所不同:
foo&& f = make_foo(1);
foo&& g(make_foo(2));
尝试使用
-std=c++11
或-std=c++14
标志编译以观察不同的结果。foo和&f
的生存期是否以与const foo&f
相同的方式延长?
foo&& f = make_foo(1);
foo&& g(make_foo(2));