【问题标题】:C++17 copy elision and object destructionC++17 复制省略和对象销毁
【发布时间】:2019-05-14 17:40:06
【问题描述】:

来自cppreference

当复制省略发生时,实现处理源和 省略的复制/移动 (C++11 起) 操作的目标只是两个 引用同一对象的不同方式,以及 该对象发生在两个对象的较晚时间 没有优化就会被破坏(除了,如果 所选构造函数的参数是一个右值引用 对象类型,销毁发生在目标本来应该是 销毁)(C++17 起)。

对于像A a = returnA(); 这样的简单案例,我可以理解在returnA() 中对象没有被销毁,而是在A a; 的情况下发生了销毁,这是后来的时间。

我想不出一种相反的情况,即复制/移动操作的源首先被破坏。我还想要一个自 C++17 以来添加的语句的示例(当所选构造函数的参数是对对象类型的右值引用时例外)

【问题讨论】:

  • 那么...您的问题到底是什么?
  • 有两个问题:在这种情况下,returnA 中创建的对象可能比它“创建”到的a 寿命更长?第二个问题是:C++17中添加的条款是什么意思:(except that, if the parameter of the selected constructor is an rvalue reference to object type, the destruction occurs when the target would have been destroyed)
  • 在这种情况下,在 returnA 中创建的对象可能比它“创建”到的 a 寿命更长?”我不确定我是否理解这个问题。引用的段落并没有说有这种情况。
  • 你的意思是“来源”还是“目标”?

标签: c++ c++17 copy-elision object-destruction


【解决方案1】:

源比目标更长寿的对称情况是纯右值是一个参数:

struct A {
  static int *data;
  A() {if(!refs++) data=new int(42);}
  A(const A&) {++refs;}  // not movable
  ~A() {if(!--refs) delete data;}
private:
  static int refs;
};
int A::refs,*A::data;
int* f(A) {return A::data;}
A returnA();
int returnInt() {return *f(returnA());} // ok

因为returnA() 的结果是临时的,所以它的生命周期会延伸到return 语句的full-expression 的末尾。实现可以用f的参数来识别它,但是当f返回时可能不会销毁它,所以returnInt中的解引用是有效的。 (注意参数may survive that long反正。)

C++17 中的调整(以及保证这样的省略)是,如果你(将)移动纯右值,它可能会在参数为时被破坏(因为你不应该无论如何都要依赖它的内容)。如果那是 f 返回时,如果 A 可移动,则上面的(不明智的)代码将无效。

【讨论】:

  • 我用移动构造函数交换了复制构造函数,并将returnInt 更改为int returnInt() {return *f(move(returnA()));}。这会产生一个调用序列A(), A(const A&&), ~A(), ~A()。这就是 C++17 调整的目的吗?
  • 这仅表明在prvalue上调用move会强制实现一个临时对象。 (在 C++14 术语中,它可以防止可选的复制/移动省略。)
  • 但是当我只将复制构造函数与移动构造函数交换时(并在其中添加了可见的 printf 副作用),我看不到移动构造函数也被调用(使用 gcc-8)。 “如果 A 可移动,上面的(不明智的)代码将变得无效”是什么意思?
  • @pterodragon: 移动构造函数没有被调用,但是它的 selection 允许 参数/参数被破坏(破坏data)在取消引用 data 之前。
  • 我假设returnA()的定义是A returnA() { {}; }?
猜你喜欢
  • 2013-10-24
  • 1970-01-01
  • 2023-02-08
  • 2019-07-27
  • 2011-09-18
  • 2010-12-31
  • 1970-01-01
  • 2019-03-01
相关资源
最近更新 更多