c++ - 删除了所有自动生成的构造函数/运算符的类仍然可以从函数返回吗?
问题描述
最近,我遇到了这个答案,它描述了如何初始化std::array
非默认可构造元素。我并不感到惊讶,因为这个答案显然没有做任何默认构造。
相反,它std::array
使用聚合初始化构造一个临时变量,然后在函数返回时移动(如果移动构造函数可用)或复制到命名变量中。所以我们只需要移动构造函数或复制构造函数可用。
或者我是这么想的……
然后是这段让我感到困惑的代码:
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)!
为什么会这样编译?foo
显然,要从函数中返回 a make_foo()
,我们必须构造 a foo
。这意味着在main()
函数中,我们foo
从返回的 中分配或构造 a foo
。这怎么可能?!
解决方案
欢迎来到保证复制省略的美妙世界(C++17 的新手。另请参阅此问题)。
foo make_foo(int x) {
return foo(x);
}
int main() {
foo f = make_foo(1);
foo g(make_foo(2));
}
在所有这些情况下,您都是foo
从类型的纯右值初始化 a foo
,因此我们只是忽略所有中间对象并直接从实际初始化程序初始化最外层的对象。这完全等同于:
foo f(1);
foo g(2);
我们甚至不在这里考虑移动构造函数——所以它们被删除的事实并不重要。具体规则是[dcl.init]/17.6.1 - 只有在这一点之后,我们才考虑构造函数并执行重载决议。
推荐阅读
- algorithm - N = 25 皇后问题。使用香草爬山算法
- python - Ubuntu 中的 Tensorflow 2.3.0:libcublas.so.10:无法打开共享对象文件
- php - 通过 url 直接用户访问页面
- amazon-web-services - 如何将 ssh 与 AWS ssm 会话和多配置文件一起使用?
- python - 替换列表中的 None 值时如何处理边缘情况?
- mysql - 过滤与 SQL 中的过滤条件相对应的重复记录和出现次数
- html - Safari 的填充计算问题
- apache-spark - 如何知道执行 pysaprk 代码需要多长时间
- ruby-on-rails - gem install pg 失败
- python - Python简单拆分器