我有一个无法上课的课程。复制这将是有问题的。我想保证它不会被复制,所以我制作了它的复制构造函数deleted
:
class A {
public:
A();
A(const A&) = delete;
};
A fun() {
return A();
};
int main() {
A a = fun();
};
不幸的是,g ++不会因为原因而编译:
t.cc: In function ‘A fun()’:
t.cc:8:12: error: use of deleted function ‘A::A(const A&)’
return A();
^
t.cc:4:5: note: declared here
A(const A&) = delete;
^
t.cc: In function ‘int main()’:
t.cc:12:13: error: use of deleted function ‘A::A(const A&)’
A a = fun();
^
t.cc:4:5: note: declared here
A(const A&) = delete;
^
但是这是一个非常明确的情况,应该使用复制省略,因此不应该调用复制构造函数。为什么会这样?
答案 0 :(得分:18)
直到C ++ 17复制省略是一种优化,编译器不需要这样做,因此类必须是可复制的,因为编译器可能想要复制(即使它实际上没有)。在C ++ 17中,许多情况下将保证复制省略,然后课程不需要复制ctors。
另见:
http://en.cppreference.com/w/cpp/language/copy_elision
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0.html
https://herbsutter.com/2016/06/30/trip-report-summer-iso-c-standards-meeting-oulu/ (关于"保证副本省略")
你也许可以使用在你的类中声明复制构造函数的旧技巧,但实际上并没有实现它?只要它不实际调用复制ctor,这应该取悦编译器。我没有测试过,但我认为它应该适用于你的情况,直到C ++ 17到来。
答案 1 :(得分:10)
你不能强制复制elision(还有)(见其他答案)。
但是,您可以为您的类提供默认移动构造函数,如果无法使用RVO / NRVO,则会移动(因此,不复制)返回值。为此,您应为移动构造函数添加= default
:
class A {
public:
A() = default;
A(const A&) = delete;
A(A&&) = default;
A& operator=(A&&) = default;
};
答案 2 :(得分:7)
返回值优化(RVO和NRVO)并不意味着要求可复制或可移动所涉及的类型被删除。无论您是否获得RVO,此要求均适用。
最可能的原因是(目前)没有执行复制省略。这是可能发生的优化,根据在特定实现中是否应用该优化,编译代码是没有意义的。
在C ++ 17中,RVO将在某些情况下被强制执行,并且可复制性和可移动性的要求将被删除。