我经常发现自己为具有许多成员变量的类编写繁琐的移动构造函数。它们看起来如下:
A(A && rhs) :
a(std::move(rhs.a)),
b(std::move(rhs.b)),
c(std::move(rhs.c)),
d(std::move(rhs.d)) {
some_extra_work();
}
也就是说,它们执行与默认移动构造函数关联的所有操作,然后执行一些平凡的额外任务。理想情况下,我会委托默认的移动构造函数然后执行额外的工作,但是定义我自己的移动构造函数的行为会阻止定义默认实现,这意味着没有任何代理权。
有没有一种很好的方法来解决这种反模式?
答案 0 :(得分:4)
更新:忽略此答案的第一部分,跳到最后有更好的解决方案。
将额外的工作包装成新类型并从中继承:
class A;
struct EW
{
EW(EW&&);
};
class A : private EW
{
friend class EW;
public:
A(A&&) = default;
};
EW::EW(EW&&) { A* self = static_cast<A*>(this); self->some_extra_work(); }
您也可以使用数据成员而不是基类来执行此操作,但是您需要使用offsetof
(对于非标准布局类型未定义)或使用手动等效使用的hackery偷偷摸摸的指针算术。使用继承允许您使用static_cast
进行转换。
如果在成员初始化后必须完成 ,这将无法工作,因为基类首先被初始化击>
或者,如果额外的工作实际上是在你移动的rvalue对象上运行的,那么你应该将成员包装成那些在移动时自动工作的类型,例如:我的tidy_ptr类型,用于实现Rule of Zero
some_extra_work()