繁体   English   中英

根据析构函数和移动构造函数实现移动赋值

[英]Implementing move assignment in terms of destructor and move constructor

假设我有一个管理内存的类,因此需要用户定义的特殊成员函数(想象vector或类似)。

考虑move-assignment运算符的以下实现:

Class& operator=(Class&& rhs)
{
    this->~Class();                    // call destructor
    new (this) Class(std::move(rhs));  // call move constructor in-place
}
  1. 以这种方式实现移动赋值运算符是否有效 也就是说,以这种方式调用析构函数和构造函数是否与语言中的任何对象生存规则相冲突?

  2. 以这种方式实现移动赋值运算符是一个好主意吗? 如果没有,为什么不,并且有更好的规范方式?

它无效:如果移动子对象的一部分调用此移动赋值怎么办? 然后你销毁孩子(假设它有一个虚拟的析构函数)并在其位置重新创建一个父对象。

我会说,即使在非虚拟环境中,它仍然是一个坏主意,因为你不经常看到语法,它可能会使代码更难以为未来的维护者。

最好的方法是避免必须完全编写自己的移动构造函数(并使用默认值),让所有的类成员都自己动手。 例如,依赖unique_ptr等。如果失败的话,似乎在交换方面实现它(作为复制分配的复制和交换)将是一个易于理解的机制。

  1. 它可能是有效的(1)。 为了解决有关dtor / ctor生命周期的具体问题,是有效的(2)。 这就是矢量的原始实现如何工作。
  2. 这可能是一个好主意(可能不是),但你可能不想要一个规范的方式。(3)

(1)关于在自我移动案件中是否需要有效或者移动是否有效存在争议。 争论自我安全是代码应该是安全的(duh),我们当然希望自我分配是安全的。 此外,一些用户体验报告说,对于许多使用移动的算法,自动移动是可能的并且很难检查。

反对自动安全的立场是整个移动语义点是节省时间的位置,因此移动应该尽可能快。 相对于搬家的成本,自动检查可能是昂贵的。 请注意,编译器永远不会生成自动移动代码,因为自然(未转换)的rvalues不能自行移动。 拥有自动移动的唯一方法是显式调用“std :: move()”强制转换。 这使得std :: move()调用者的负担要么验证不涉及自动移动,要么说服自己不是。 还要注意,创建一个用户定义的等效“std :: move”来检查自动移动然后什么都不做是很简单的。 如果您不支持自动移动,则可能需要记录该操作。

(2)这不是模板,因此您可以知道表达式是否为“new(this)Class(s​​td :: move(rhs));” 可以投掷。 如果可以,那么不,这是无效的。

(3)这段代码可能是维护人员的难题,他们可能期望采用更传统的交换方法,但交换方法存在潜在的缺陷。 如果目标释放的资源需要尽快释放(例如互斥锁),则交换的缺点是资源被交换到移动源对象中。 如果移动是调用“std :: move()”的结果,则移动源对象可能不会立即被丢弃。 (由于这不是模板,您可以知道正在释放哪些资源。如果内存是唯一被释放的资源,那么这不是问题。)

一种更好的方法可能是从析构函数中分解资源释放代码,从移动构造函数中分解资源移动代码,然后在此移动赋值运算符中调用这些(内联)例程。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM