如何强制执行复制 elision,为什么它不适用于已删除的复制构造函数?

How to enforce copy elision, why it won't work with deleted copy constructor?

本文关键字:复制 适用于 删除 构造函数 不适用 强制执行 elision 为什么      更新时间:2023-10-16

我有一个无法复制的类。 复制这个会有问题。我想保证它永远不会被复制,所以我把它的复制构造函数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;
     ^

但这是一个非常明显的情况,应该使用复制 elision,所以不应该调用复制构造函数。为什么会这样?

直到 C++17 年,复制 elision 是编译器不需要做的优化,因此类必须是可复制的,因为编译器可能想要复制(即使它实际上不需要)。在 C++17 中,在许多情况下可以保证复制 elision,然后类就不需要复制 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 到来。

您还不能强制复制省略(请参阅其他答案)。

但是,您可以为类提供默认的移动构造函数,如果 RVO/NRVO 不可行,这将移动(因此不会复制)返回值。为此,您应该为移动构造函数添加= default

class A {
  public:
    A() = default;
    A(const A&) = delete;
    A(A&&) = default;
    A& operator=(A&&) = default;
};

返回值优化(RVO 和 NRVO)并不意味着删除可复制或可移动所涉及的类型的要求。无论您是否获得 RVO,此要求都适用。

最可能的原因是(目前)没有强制执行复制省略。这是可能发生的优化,根据该优化是否应用于特定实现,代码编译或不编译是没有意义的。

在 C++17 中,RVO 将在某些情况下强制执行,并且将放弃可复制性和可移动性的要求。