为什么我们需要在move构造函数中将右值引用设置为null
Why do we need to set rvalue reference to null in move constructor?
//code from https://skillsmatter.com/skillscasts/2188-move-semanticsperfect-forwarding-and-rvalue-references
class Widget {
public:
Widget(Widget&& rhs)
: pds(rhs.pds) // take source’s value
{
rhs.pds = nullptr; // why??
}
private:
struct DataStructure;
DataStructure *pds;
};
我无法理解将rhd.pds
设置为nullptr
的原因。
如果我们删除这一行会发生什么:rhs.pds = nullptr;
该类的一些详细信息已被删除。特别是,构造函数动态分配DataStructure
对象,析构函数将其解除分配。如果在移动过程中,您只是将指针从一个Widget
复制到另一个,那么两个Widget
都将具有指向相同分配的DataStructure
对象的指针。然后,当这些对象被销毁时,它们都会尝试delete
它。这将给出未定义的行为。为了避免这种情况,要从中移动的Widget
将其内部指针设置为nullptr
。
这是实现移动构造函数时的标准模式。您希望将一些动态分配的对象的所有权从一个对象移动到另一个对象,因此需要确保原始对象不再拥有这些分配的对象。
从图表上看,您从这种情况开始,希望将DataStructure
的所有权从一个Widget
转移到另一个:
┌────────┐ ┌────────┐
│ Widget │ │ Widget │
└───╂────┘ └────────┘
┃
▼
┌───────────────┐
│ DataStructure │
└───────────────┘
如果你只是复制了指针,你会得到:
┌────────┐ ┌────────┐
│ Widget │ │ Widget │
└───╂────┘ └───╂────┘
┗━━━━━━━━┳━━━━━━━┛
▼
┌───────────────┐
│ DataStructure │
└───────────────┘
如果您随后将原始Widget
指针设置为nullptr
,则您有:
┌────────┐ ┌────────┐
│ Widget │ │ Widget │
└────────┘ └───╂────┘
┃
▼
┌───────────────┐
│ DataStructure │
└───────────────┘
所有权已经成功转移,并且当两个Widget
都可以被销毁时,不会造成未定义的行为。
DataStructure
对象很可能由Widget
"拥有",重置指针可防止Widget
被破坏时意外删除。
或者,当对象从中移出时,通常会将其重置为"空"或"默认"状态,而重置指针是遵循惯例的无害方式。
class Widget {
public:
Widget(Widget&& rhs)
: pds(rhs.pds) // take source’s value
{
rhs.pds = nullptr; // why??
}
~Widget() {delete pds}; // <== added this line
private:
struct DataStructure;
DataStructure *pds;
};
我在上面的类中添加了一个析构函数。
Widget make_widget() {
Widget a;
// Do some stuff with it
return std::move(a);
}
int main {
Widget b = make_widget;
return 0;
}
为了说明如果删除nullptr赋值会发生什么,请检查以上方法。小部件A将在助手功能中创建并分配给小部件b。
由于小部件a超出了它调用的析构函数的作用域,它会释放内存,而留给您的是指向无效内存地址的小部件b。
如果将nullptr分配给rhs,则还会调用析构函数,但由于删除nullptr什么都不做都好:)
- 为什么将一个结构的引用设置为等于另一个结构只会更改一个数据成员?
- C++(和 ROS) - 包含与前向声明引用,设置默认值和类型定义
- 如何在引用上设置数据断点
- 使用 sscanf 设置结构引用的值
- 将函数的引用设置为其他 c++ 文件中的非静态函数
- 通过初始化列表设置抽象类的引用
- 将常量引用成员设置为临时变量是否安全
- 对象超出范围后,引用成员设置为 0
- 为什么设置/get_default_resource使用指针而不是引用?
- 在构造函数中设置引用?
- 如何在构造函数之后设置引用?
- 通过引用设置类时会发生什么情况
- 从函数返回 libconfig 类设置对象引用
- qt vsaddin错误对象引用未设置为对象的istanse
- 为什么我们需要在move构造函数中将右值引用设置为null
- 智能指针:通过引用设置、重置、设置null、null检查或重置检查
- 为通过引用设置参数的函数命名的样式
- 是否可以在没有常量的情况下将类对象引用设置为c++中的默认参数
- 删除对象会将其引用设置为NULL
- 将引用设置为第二个变量