以下代码工作得很好(显示 RVO):
struct A {
A (int) { cout << "A::A()\n"; } // constructor
A (const A&) { cout << "A::A(const A&)\n"; } // copy constructor
};
A foo () { return A(0); }
int main () {
A a = foo();
}
Output:
A::A() // --> which means copy constructor is not called
如果我将复制构造函数标记为explicit
:
explicit A (const A&) { ... }
然后编译器报错:
explicit.cpp: In function ‘A foo()’:
explicit.cpp:10:22: error: no matching function for call to ‘A::A(A)’
A foo () { return A(0); }
^
explicit.cpp:5:3: note: candidate: A::A(int)
A (int) { cout << "A::A()\n"; }
^
explicit.cpp:5:3: note: no known conversion for argument 1 from ‘A’ to ‘int’
explicit.cpp: In function ‘int main()’:
explicit.cpp:14:13: error: no matching function for call to ‘A::A(A)’
A a = foo();
^
explicit.cpp:5:3: note: candidate: A::A(int)
A (int) { cout << "A::A()\n"; }
^
explicit.cpp:5:3: note: no known conversion for argument 1 from ‘A’ to ‘int’
为什么会发生这种情况,RVO 不应该按原样工作吗?
RVO 可以删除副本,但语言规则要求副本(或移动)必须仍然是可能的:
[C++14: 12.8/31]:
当满足某些条件时,允许实现省略类对象的复制/移动构造,即使为复制/移动操作选择的构造函数和/或对象的析构函数具有副作用。[..]
[C++14: 12.8/32]:
[..] [ Note:无论是否发生复制省略,都必须执行此两阶段重载决策。如果不执行省略,它确定要调用的构造函数,并且即使省略调用,所选构造函数也必须可访问。——尾注]
您通过添加使复制变得不可能explicit
,并且移动是不可能的,因为您的复制构造函数会阻止创建隐式定义的移动构造函数。
您可以通过添加自己的移动构造函数(也许是默认的构造函数)来允许移动:
A(A&&) = default;
但这只是遵守同一语言规则的另一种方式。
无论如何,C++17 将通过添加一些不受此约束的复制省略保证来稍微放宽该规则。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)