看一下下面的代码示例,该示例使用类似于uncopiable
的boost::noncopyable
类:
#include <vector>
class uncopiable {
using self = uncopiable;
protected:
uncopiable() {}
~uncopiable() {}
uncopiable(const self&) = delete;
self& operator=(const self&) = delete;
};
struct A {
struct B : uncopiable {
using self = B;
B() {
}
B(B&&) = default;
self& operator=(B&&) = default;
~B() {
}
};
A() { v.emplace_back(); }
~A() {}
private:
std::vector<B> v;
};
int main () {}
因为我只想移动内部类,所以我明确地将其移动构造函数和赋值运算符指定为默认值,而且由于我听说在这种情况下指定所有“特殊成员函数”是一种好习惯,因此我继承了它来自
uncopiable
。问题是每个编译器编译都会失败,并且会显示类似以下错误消息的内容(此消息摘自clang消息):可以通过删除继承来解决此问题(仍然不会创建复制操作)。但是写复制操作以在类之后显式删除也是可以的。
我的问题是:为什么会发生?是否可以认为是通过继承辅助类来禁用构造函数/赋值运算符的缺陷?
最佳答案
问题是您的uncopiable
类不可移动。因此,派生类的default
move构造函数/赋值运算符尝试使用delete
d复制版本。
static_assert(std::is_move_constructible<uncopiable>::value, ""); // fails
static_assert(std::is_move_assignable<uncopiable>::value, ""); // fails
原因是§12.8¶9:
将复制运算符或赋值运算符声明为
delete
d仍视为声明它。解决方案当然是声明
uncopiable
的移动操作。uncopiable(uncopiable&&) noexcept = default;
uncopiable& operator=(uncopiable&&) noexcept = default;
注意move operations should usually be declared
noexcept
。特别是如果您想像示例中那样在std::vector
中使用类型。