RValue引用是否在将其绑定到另一个指针后删除它们的绑定(非指针)对象?

问题描述 投票:1回答:1

简短而简单的问题:

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

出于同样的原因,我假设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函数有哪些方法?

c++ rvalue-reference
1个回答
2
投票

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

你没有。这是一种常见的模式,但它对于移动语义的工作方式并不重要。你需要做的是设置这样的东西,以便移动对象的破坏不会弄乱移动的对象。对于析构函数将要释放的指针,将它们设置为nullptr是明显的选择,但将单独的bool m_hasBeenMovedFrom成员设置为true也会起作用,就像将指针设置为指向新分配的对象一样。

但重要的是,右值引用本身不会做那样的事情。 Rvalue引用只是引用的变体,与lvalue引用的绑定语义略有不同。除了左值引用之外,它们不会删除任何内容。

在您发布的代码中,构造函数正在接收对象的右值引用,并存储指向该对象的指针。那是危险的,因为你可以做像Foo f(3)(或者,因为它是一个非explicit单参数构造函数,甚至只是将3传递给期望Foo的函数),这会将指针存储到一个到期值。另一方面,如果传入的对象保证比Foo更长,一切都会好的,但是如果你需要这个,为什么要使用右值引用呢?

总的来说,虽然你在那里展示的代码本身并没有未定义的行为,但绝对是在使用类时要求UB发生。右值参考的内涵是“这个物体将很快消失,所以随意窃取它的随身物品”。一个int没有任何物品,所以这没有用......因为它即将消失,你不想指挥它。

顺便提一下,您经常会看到template<typename T> someFunc(T && arg)形式的标准库函数(和其他函数!)。这不是一个右值参考,而是一个“转发参考”,也就是一个“通用参考”,大量的页面会告诉你(但this是我最喜欢的)。这里要记住的主要事情是,如果T &&给出一个rvalue,它只会像右值引用一样,并且函数本身需要注意不要无条件地将其视为右值引用。

© www.soinside.com 2019 - 2024. All rights reserved.