iam*_*ind 2 c++ compiler-errors explicit copy-constructor return-value-optimization
以下代码完美正常(显示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();
}
Run Code Online (Sandbox Code Playgroud)
输出:
A::A() // --> which means copy constructor is not called
Run Code Online (Sandbox Code Playgroud)
如果我将复制构造函数标记为explicit:
explicit A (const A&) { ... }
Run Code Online (Sandbox Code Playgroud)
然后编译器出错了:
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’
Run Code Online (Sandbox Code Playgroud)
为什么会发生这种情况,RVO不应该按原样工作吗?
RVO可以删除副本,但语言规则要求仍然可以复制(或移动):
[C++14: 12.8/31]:当满足某些条件时,允许实现省略类对象的复制/移动构造,即使为复制/移动操作选择的构造函数和/或对象的析构函数具有副作用.[..]
[C++14: 12.8/32]:[..] [注意:无论是否发生复制省略,都必须执行此两阶段重载决策.如果未执行elision,它将确定要调用的构造函数,并且即使调用被省略,也必须可以访问所选的构造函数. - 尾注]
您通过添加使副本无法进行explicit,并且无法进行移动,因为您的复制构造函数会阻止创建隐式定义的移动构造函数.
您可以通过添加自己的移动构造函数来允许移动,也许是默认的移动构造函数:
A(A&&) = default;
Run Code Online (Sandbox Code Playgroud)
但这只是遵守相同语言规则的另一种方式.
C++ 17无论如何都会放松规则,通过添加一些不受此约束限制的复制省略的保证.