查看以下代码示例,该示例使用与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):
/ usr / include / c ++ / v1 / memory:1645:31:错误:调用'A :: B'的隐式删除的复制构造函数
...
main.cpp:26:10:注意:在实例化函数模板特化'std :: __ 1 :: vector&gt; :: emplace_back&lt;&gt;'请求
main.cpp:19:3:注意:复制构造函数被隐式删除,因为'B'有一个用户声明的移动构造函数
可以通过删除继承来修复(仍然不会创建复制操作)。但是在此之后编写复制操作以在类中显式删除也是可以的。
我的问题是:为什么会发生?是否可以认为通过继承辅助类来禁用构造函数/赋值运算符?
答案 0 :(得分:4)
问题是您的uncopiable
课程无法移动。因此,派生类的default
移动构造函数/赋值运算符尝试使用delete
d副本版本。
static_assert(std::is_move_constructible<uncopiable>::value, ""); // fails
static_assert(std::is_move_assignable<uncopiable>::value, ""); // fails
原因是§12.8¶9:
如果类
时,将隐式声明一个默认值。X
的定义未明确声明移动构造函数,则当且仅当
X
没有用户声明的复制构造函数,X
没有用户声明的副本分配运算符X
没有用户声明的移动赋值运算符和X
没有用户声明的析构函数。
将复制运算符或赋值运算符声明为delete
d仍然计为声明它。
解决方案当然是为uncopiable
声明移动操作。
uncopiable(uncopiable&&) noexcept = default;
uncopiable& operator=(uncopiable&&) noexcept = default;
请注意move operations should usually be declared noexcept
。特别是如果你想在你的例子中使用std::vector
中的类型。
答案 1 :(得分:0)
这在MinGw上编译正确:
#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&&) {};
self& operator=(B&&) = default;
~B() {
}
};
A() { v.emplace_back(); }
~A() {}
private:
std::vector<B> v;
};
int main () {
A* a = new A();
}