简短的问题:
我知道在移动构造函数/重载赋值中,您必须设置引用指向 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/