c++ - RValue 引用在分配给另一个指针后是否删除它们的绑定(bind)(非指针)对象?

标签 c++ rvalue-reference

简短的问题:

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

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

我的问题是与以下类似的代码片段是否定义了行为(如果我使用 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 等标准函数使用哪些方法?

最佳答案

I am aware that in a move constructor / overloaded assignment you must set RValue references that refer to pointers to nullptr (at the end) in order to avoid deallocation of that resource.

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

不过,重要的是右值引用它们自己不会做那样的事情。右值引用只是引用的一种变体,与左值引用的绑定(bind)语义略有不同。它们不会像左值引用那样删除任何东西。

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

总的来说,虽然您在那里显示的代码本身 没有未定义的行为,但绝对乞求在使用该类时发生 UB。右值引用的含义是“这个对象很快就会消失,所以尽管偷走它的东西”。一个int没有任何元素,所以这没有用......而且因为它即将消失,所以你不想持有指向它的指针。

顺便说一下,您会经常看到 template<typename T> someFunc(T && arg) 形式的标准库函数(和其他函数!) .这不是右值引用,而是“转发引用”,又名“通用引用”,大量页面会告诉您(但 this 是我最喜欢的)。这里要记住的主要事情是 T &&只有在给定右值时才会像右值引用一样工作,并且函数本身需要注意不要无条件地将其视为右值引用。

关于c++ - RValue 引用在分配给另一个指针后是否删除它们的绑定(bind)(非指针)对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55040758/

相关文章:

c++ - Const Rvalue 引用以捕获不应编译的重载

c++ - 完美转发 l-value ref 和 r-value ref 和非 ref 类型的可变参数模板?

c++ - 调用了错误类型的显式构造函数

c++ - 不正常的退出会破坏 C++ 内存分配器吗?

c++ - 为什么不能使用嵌套的初始化程序列表初始化std::array <std::pair <int,int>,3>,但是std::vector <std::pair <int,int >>可以初始化?

c++ - 按值传递与 const & 和 && 重载

c++ - 为什么 std::as_const(T &&v) 不能移动返回它的参数?

c++ - 良好编程习惯中已发送消息的唯一标识符

android - cv::cvtColor 没有分配内存问题

c++ - 关于捕获异常的良好做法