RValue引用分配给另一个指针后,是否会删除其绑定(非指针)对象?

时间:2019-03-07 09:52:10

标签: c++ rvalue-reference

简短的问题:

我知道,在移动构造函数/重载分配中,必须设置RValue引用,该引用引用指向nullptr的指针(最后),以避免该资源的重新分配。

出于同样的原因,我假设RValue引用在分配给另一个指针之后删除了它们的绑定(非指针)对象,这意味着此后指针的行为是不确定的。 (我不确定这是否是真的)

我的问题是,与以下类似的代码段是否已定义行为(如果我要使用pNum)? :

//Foo.h
class Foo {
    public:
        Foo(int &&num);
    private:
        int *pNum;
};

//Foo.cpp
Foo::Foo(int &&num)
:pNum(&num)//Would using/dereferencing pNum in the future cause defined behaviour? 
{}

如果这是通过将RValue引用用作参数来优化函数的错误方法,那么正确的方法是什么?例如诸如emplace或make_shared之类的std函数使用什么方法?

1 个答案:

答案 0 :(得分:2)

  

我知道,在移动构造函数/重载分配中,必须设置RValue引用(指向末尾指向nullptr的指针),以避免释放该资源。

你不知道。这是一种常见的模式,但对于移动语义的工作方式却不是基础。您需要做的是进行设置,以使对移出对象的破坏不会弄乱移入对象。对于析构函数将要释放的指针,将它们设置为nullptr是显而易见的选择,但是将单独的bool m_hasBeenMovedFrom成员设置为true也可以,将指针设置为point到新分配的对象。

但是重要的是,右值引用自己不会做任何类似的事情。右值引用只是引用变体,其绑定语义与左值引用略有不同。他们不会像左值引用那样删除东西。

在发布的代码中,构造函数正在接收对对象的右值引用,并存储指向该对象的指针。这很危险,因为您可以执行类似Foo f(3)的操作(或者,因为它是非{explicit的单参数构造函数,所以甚至只需将3传递给期望Foo的函数即可) ),它将存储指向到期值的指针。另一方面,如果保证传入的对象的生存期Foo没问题,但是如果您需要这样做,为什么还要使用右值引用?

总的来说,尽管您在此处显示的代码没有本身具有未定义的行为,但使用类时UB发生绝对是乞求。右值引用的含义是“该对象将很快消失,因此可以随时窃取其所有物”。 int没有任何物品,因此无济于事……并且由于它即将消失,因此您不希望持有指向它的指针。

偶然地,您经常会看到template<typename T> someFunc(T && arg)形式的标准库函数(和其他函数!)。那不是 右值引用,而是“转发引用”,也就是“通用引用”,大量页面会告诉您有关信息(但是this是我最喜欢的)。这里要记住的主要事情是,T &&仅在被赋予右值的情况下才会像右值引用一样工作,并且函数本身需要注意不要无条件地将其视为右值引用。