隐式移动构造函数何时不够好?
我应该像破坏者和复制构造函数那样对待它,通常只有在我管理自己的内存时才需要它吗?
隐式移动构造函数在这个(非常人为的)场景中是否足够好:
class A
{
private:
B b;
std::string name;
public:
A();
std::string getName() const {
return name;
}
B getB() const {
return b;
}
};
class B
{
private:
std::vector list;
public:
B();
std::vector getList() const {
return list;
}
};
答案 0 :(得分:24)
此处的答案基于Google搜索结果。
> 我什么时候应该为我的班级定义移动构造函数?
这在很大程度上取决于你的班级做了什么以及如何实施。首先,对于“聚合”类,为了方便/清晰,仅将其他数据分组,移动构造函数将由编译器隐式生成。考虑以下课程。
struct Country { std::string name; std::vector<std::string> cities; };
在典型的C ++结构中,许多特殊的成员函数(如复制构造函数,复制赋值,析构函数)都是自动生成的。这还包括移动构造函数(和移动赋值)。
对于更复杂的类,它们封装了它们的实现细节,答案更有趣。移动语义(移动构造函数,移动赋值)的主要目标之一是为编译器提供两个工具,用于实现用户定义类型的值语义(按值传递参数,按值返回):
- 制作两个相同的物品 - 它需要很昂贵。
- 将一个对象从一个内存位置移动到另一个内存位置 - 它可以是 非常快。
醇>如果您的类可以实现比复制构造函数更快的移动构造函数,那么您应该将其实现为运行时速度优化目的。我们已经看到它是如何实现的对于this link中的向量。但是,并不是所有类型都可以实现比复制构造函数更快的移动构造函数。考虑以下矩阵表示。
class Matrix { std::complex<long double> data[1000][1000]; };
因为矩阵表示所需的所有内存都是在类范围内声明的(与使用堆分配的内存的向量不同),所以无法仅应用少量的赋值。我们需要为每个数组元素进行复制。定义移动构造函数没有意义,因为它不会比复制快。
提供移动构造函数的另一个正当理由是,如果要启用不可复制的类型(因为它类似RAII并且代表资源)仍然需要通过不需要复制的值传递,并存储在STL容器中。 this link更详细地解释了这种独特的所有权语义。
答案 1 :(得分:16)
强制性Rule of Zero答案:设计管理单个资源的类 - 从而覆盖移动/复制/析构函数/赋值 - 或者聚合资源管理器且不需要覆盖的类。