如何强制复制省略,为什么它不能与删除的复制构造函数一起使用?
How to enforce copy elision, why it won't work with deleted copy constructor?
我有一个无法复制的class。复制这个会有问题。我想保证它永远不会被复制,所以我制作了它的复制构造函数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;
^
但这是一个非常明确的情况,应该使用复制省略,所以永远不应该调用复制构造函数。为什么会这样?
你不能强制复制省略(目前)(见其他答案)。
但是,您可以为 class 提供默认的移动构造函数,如果 RVO/NRVO 不可能,这将移动(因此不会复制)return 值。为此,您应该为移动构造函数添加 = default
:
class A {
public:
A() = default;
A(const A&) = delete;
A(A&&) = default;
A& operator=(A&&) = default;
};
Return值优化(RVO和NRVO)并不意味着要求去掉copyable或movable涉及的类型。无论您是否获得 RVO,此要求都适用。
最可能的原因是复制省略没有(当前)强制执行。这是一种 可能 发生的优化,根据该优化是否应用于特定实现,代码是否编译没有意义。
在C++17中,RVO在某些情况下会被强制执行,可复制性和可移动性的要求将被取消。
直到 C++17 复制省略是编译器不需要执行的优化,因此 classes 必须是可复制的,因为编译器可能想要复制(即使它实际上不需要)。在 C++17 中,在许多情况下将保证复制省略,然后 classes 将不需要复制构造函数。
另请参阅:
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/
(关于"Guaranteed copy elision"的一点)
您或许可以使用在 class 中声明复制构造函数的老把戏,但实际上并不实现它?只要编译器实际上不调用复制构造函数,那应该会让编译器满意。我没有对此进行测试,但我相信在 C++17 到来之前它应该适用于您的情况。
我有一个无法复制的class。复制这个会有问题。我想保证它永远不会被复制,所以我制作了它的复制构造函数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;
^
但这是一个非常明确的情况,应该使用复制省略,所以永远不应该调用复制构造函数。为什么会这样?
你不能强制复制省略(目前)(见其他答案)。
但是,您可以为 class 提供默认的移动构造函数,如果 RVO/NRVO 不可能,这将移动(因此不会复制)return 值。为此,您应该为移动构造函数添加 = default
:
class A {
public:
A() = default;
A(const A&) = delete;
A(A&&) = default;
A& operator=(A&&) = default;
};
Return值优化(RVO和NRVO)并不意味着要求去掉copyable或movable涉及的类型。无论您是否获得 RVO,此要求都适用。
最可能的原因是复制省略没有(当前)强制执行。这是一种 可能 发生的优化,根据该优化是否应用于特定实现,代码是否编译没有意义。
在C++17中,RVO在某些情况下会被强制执行,可复制性和可移动性的要求将被取消。
直到 C++17 复制省略是编译器不需要执行的优化,因此 classes 必须是可复制的,因为编译器可能想要复制(即使它实际上不需要)。在 C++17 中,在许多情况下将保证复制省略,然后 classes 将不需要复制构造函数。
另请参阅:
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/ (关于"Guaranteed copy elision"的一点)
您或许可以使用在 class 中声明复制构造函数的老把戏,但实际上并不实现它?只要编译器实际上不调用复制构造函数,那应该会让编译器满意。我没有对此进行测试,但我相信在 C++17 到来之前它应该适用于您的情况。