28

什么时候隐式移动构造函数不够好?

我是否应该将它视为析构函数和复制构造函数,通常只有在我管理自己的内存时才需要它?

在这个(非常做作的)场景中,隐式移动构造函数是否足够好:

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;
    }
};
4

2 回答 2

24

这里的答案是基于谷歌搜索的结果。

引用Andrzej 的 C++ 博客

> 我什么时候应该为我的班级定义移动构造函数?

这在很大程度上取决于你的类做什么以及它是如何实现的。首先,对于“聚合”类,为了方便/清晰而只对其他数据进行分组,移动构造函数将由编译器隐式生成。考虑下面的课程。

struct Country {
  std::string name;
  std::vector<std::string>  cities;
};

在典型的 C++ 结构中,许多特殊的成员函数——如复制构造函数、复制赋值、析构函数——是自动生成的。这还包括移动构造函数(和移动赋值)。

对于更复杂的类,它们封装了它们的实现细节,答案更有趣。移动语义(移动构造函数、移动赋值)的主要目标之一是为编译器提供两个工具来实现用户定义类型的值语义(按值传递参数、按值返回):

  1. 用一个制作两个相同的物体——它需要很昂贵。
  2. 将一个对象从一个内存位置移动到另一个内存位置——它可以做得非常快。

如果您的类可以实现比复制构造函数更快的移动构造函数,则应该出于运行时速度优化的目的而实现它。我们已经在此链接中看到了如何为矢量实现它。但是,并非所有类型都可以实现这种比复制构造函数更快的移动构造函数。考虑以下矩阵表示。

class Matrix {
  std::complex<long double> data[1000][1000];
};

因为矩阵表示所需的所有内存都在类范围内声明(与使用堆分配内存的向量不同),所以无法仅应用少量赋值。我们需要对每个数组元素进行复制。定义移动构造函数没有意义,因为它不会比复制快。

如果您希望使不可复制的类型(因为它类似于 RAII 并表示资源)在不需要复制的情况下仍按值传递并存储在 STL 容器中,则提供移动构造函数的另一个正当理由。此链接中更详细地解释了这种独特的所有权语义。

于 2013-06-13T22:49:21.117 回答
16

零回答的强制性规则:设计管理单个资源的类 - 从而覆盖移动/复制/析构函数/分配 - 或聚合资源管理器并且不需要覆盖的类。

于 2013-06-14T07:20:32.217 回答