右值引用总结

  1. 右值引用若不作为函数参数使用,基本等于滥用

2.

std::vector<int>&& return_vector(void)
{
    std::vector<int> tmp {1,2,3,4,5};
    return std::move(tmp);
}

std::vector &&rval_ref = return_vector();
这段代码会造成运行时错误,主要原因是右值引用实际上也只是一个与某个对象绑定的别名,
而这段代码中的rval_ref绑定到的目标是return_vector返回的一个从tmp中由move剥离出的临时对象,这个临时对象随着return_vector的调用结束也被销毁,如果后面代码中对rval_ref的会引起运行时错误

3.
a=std::move(b)
如果移动语义只是实现了简单的交换,那么交换之后的效果仅仅是a和b两个变量名持有的对象的互换,没有东西被销毁.当然a之前持有的对象最终会被销毁,也就是说当b离开作用域之后,除非是b又和别的对象进行了移动操作,在这种情况下a之前持有的对象再次被传递.因此,对于拷贝赋值运算符的实现者来说他们并不知道a以前持有的对象何时会被销毁,所以从某种意义上来说此时我们的析构是不确定的,一个变量已经通过赋值操作被覆盖了,但是这个变量之前持有的对象依然在内存的某个地方,对于在销毁时对别处代码的执行没有副作用的对象来说这当然没问题,但是如果对象在销毁时有副作用,比如在析构函数中released a lock , 这很可能出现难以查找的bug,因此在编写那些进行销毁时具有副作用的对象的用右值引用重载的拷贝赋值运算符时要显示执行那些副作用操作以清理现场,防止产生莫名其妙的bug

X& X::operator=(X&& rhs)
{
    // Perform a cleanup that takes care of at least those parts of the destructor that have side effects
    // Be sure to leave the object in a destructible and assignable state.

    // move semantics : exchange content between this and rhs    [ swap(*this,rhs) ]

    return *this;
}
    4.
void foo(X&& x)
{
  X anotherX = x;
  // ...
}

假设X实现了拷贝构造和移动构造,那么在构造anotherX时使用的是哪一种构造?
很显然参数是右值引用,但其实在用这个右值引用的参数构造anotherX时用的是拷贝构造而不是移动构造,原因是:
① 在执行完 X anotherX = x ; 之后,形参x still in the scope !! 这样如果后后面的代码再用到x那就很危险了,因为移动构造根本就不保证移动之后rhs里面有什么东西,它只保证rhs有效以及能被安全析构,
② 移动构造被调用的情况有两种,rhs是一个prvalue,或者是xrvalue (std::move(左值)) , 而这里的形参x是具名的,虽然他是一个右值引用但它本身其实是个左值,

综上,在构造anotherX时调用的是拷贝构造

猜你喜欢

转载自blog.csdn.net/u010742342/article/details/80725536
今日推荐