我经常发现自己为具有许多成员变量的类编写繁琐的移动构造函数.它们看起来如下:
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();
}
Run Code Online (Sandbox Code Playgroud)
也就是说,它们执行与默认移动构造函数关联的所有操作,然后执行一些普通的额外任务.理想情况下我会委托给默认的移动构造函数然后执行额外的工作,但是我定义自己的移动构造函数的行为阻止了默认的实现被定义,表示没有什么可以委托.
有没有一种很好的方法来绕过这种反模式?
更新:忽略这个答案的第一部分并跳到有更好解决方案的最后部分。
将额外的工作包装在新类型中并继承它:
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(); }
Run Code Online (Sandbox Code Playgroud)
您也可以使用数据成员而不是基类来完成此操作,但是您需要使用一些技巧offsetof(对于非标准布局类型未定义)或使用偷偷摸摸的指针算术的手动等效项。使用继承允许您用于static_cast转换。
some_extra_work()如果必须在成员初始化之后执行此操作,则此操作将不起作用,因为首先初始化基类。
或者,如果额外的工作实际上是在您要从中移动的右值对象上进行操作,那么您应该将成员包装在移动时自动执行该操作的类型中,例如我的tidy_ptr类型,我用它来实现零规则
class A
{
tidy_ptr<D> d;
public:
A() = default;
A(const A&) = default;
A(A&& r) = default; // Postcondition: r.d == nullptr
};
Run Code Online (Sandbox Code Playgroud)