在赋值运算符中移动语义-副作用,破坏
move semantics inside assignment operator - side effects, destruction
强制移动语义
所以从某种意义上说,我们已经进入了这里的非确定性破坏:一个变量被分配给,但是该变量以前持有的对象仍然存在某个地方只要能摧毁那个物体就没问题没有任何对外界可见的副作用但是有时析构函数确实有这样的副作用。例如解除析构函数内部的锁。因此应该对有副作用的物体进行销毁显式地在副本赋值的右值引用重载中操作员:
X& X::operator=(X&& rhs)
{
// Perform a cleanup that takes care of at least those parts of the
// destructor that have side effects. Be sure to leave the object
// in a destructible and assignable state.
// Move semantics: exchange content between this and rhs
return *this;
}
我知道l-value的原始对象通常会在NON赋值的情况下被销毁。
但是,在赋值运算符中,为什么要使用相同的行为
好吧,你必须做你的家务:你负责将旧对象修改为(安全的)可破坏状态(如果你很好,甚至修改为一般有效的对象状态)。一切都有代价(甚至移动语义)。
例如,对于典型的矢量实现:
V& V::operator=(V&& old){
auto trash = this->data;
this->data = old.data;
//cleanup
delete[] trash;
old.data = nullptr; // expecting delete[] of the destructor of old
}
你支付了三个额外的任务(只需一个swap()
技巧就可以优化)和给自己带来的小不便。你大概避免了一万个签名。值得,不是吗?
此外,如果你在析构函数中使用危险的副作用(你不应该这样做),这将不是你遇到的唯一问题。如果你认为移动作业对你的班级有危险,你也可以禁用它。
在更仔细地重读上面的段落后,我"看到"了答案:当析构函数中有副作用时,您希望能够控制这些副作用何时发生。如果你没有在赋值运算符中显式地破坏原始lhs对象,那么你就无法直接控制何时调用它的析构函数;稍后添加一些代码可能会延长该对象的使用寿命。为什么这很重要?就像链接所说的,如果你的对象只是像Queue<int>
这样的数据,那么谁在乎它什么时候被破坏。但是,如果您的对象持有影响其他对象的锁或其他资源,那么您希望所述资源的释放是确定性的。
相关文章:
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 看起来is_nothrow_constructible_v()在MSVC中被破坏了,我错了吗
- 未声明的标识符编译暗黑破坏神 2 程序"muleview"
- 为什么返回 NULL 不会破坏函数?
- 为什么Q_OBJECT会破坏QDoc?
- 如何在不破坏现有应用程序的情况下更改 API 中 stl 容器的数据类型?
- 为什么显式模板实例化不会破坏 ODR?
- 插入一个基本的单向链表节点似乎破坏了我的 c++ 代码?
- 为什么 Glib::VariantBase::store 方法破坏了给定缓冲区的开始
- 在调用其析构函数之前,是否有任何实际理由检查某些东西是否可破坏?
- ostream 运算符<< 为获取 STL 容器而过载,传递 std::string 会破坏它?
- 复制构造函数的奇怪副作用
- 0 的 2D 数组 不相关循环的破坏逻辑 - C++
- 在等待时破坏condition_variable
- 为什么添加析构函数(甚至是空的)会破坏我的结构,该结构使用 ref 转发和折叠来保存 ref 或值的副本?
- std::p air 会破坏其动态分配的对象吗?
- 为什么std::string在初始值被破坏后仍然有效
- 程序只适用于包含(无副作用)cout声明
- 为什么匿名unique_ptr值会立即被破坏
- 在赋值运算符中移动语义-副作用,破坏