移动构造函数相对于采用 bool 表示是复制还是移动的复制构造函数有什么优势?

What is the advantage of a move constructor over a copy constructor that takes a bool that says whether to copy or move?

为什么我们需要 C++ 中的移动 constructor/assignment 运算符,而我们只能这样做:

Foo(const Foo& x, bool copy = false) {
    if (copy) {
        // copy
    }
    else {
        // move
    }
}

还是我遗漏了什么?

类 在 C++ 中可以表示任何东西。文件、线程、字符串、3d 对象 - 所有这些都可以表示为某些 class 的实例。这些对象可能有很多内部数据。考虑以下示例:

class Image
{
protected:
  Ubyte* _data;
  Size _size;
  PixelFormat _pixel_format;

public:
  Image()
  :  _data(nullptr)
  ,  _size(0,0)
  ,  _pixel_format(PixelFormat::Unknown)
  {
  }

  Image(Image&& source)
  :  _data(nullptr)
  ,  _size(0,0)
  ,  _pixel_format(PixelFormat::Unknown)
  {
    this->Swap(source);
  }

  Image(const Image& origin)
  :  _data(nullptr)
  ,  _size(0,0)
  ,  _pixel_format(PixelFormat::Unknown)
  {
    this->InitWithDeepCopyOf(origin);
  }

  void Swap(Image& other)
  {
    std::swap(this->_data, other._data);
    std::swap(this->_size, other._size);
    std::swap(this->_pixel_format, other._pixel_format);
  }
};

InitWithDeepCopyOf(const Image& img) 使用存储在 img 中的数据初始化图像,但它首先完整复制该数据(考虑具有全高清分辨率的 32bpp 图像 - InitWithDeepCopyOf() 将复制 8.3MB 的数据!)。

在我们的程序中,还有一个class:

class ImageHolder
{
protected:
  Image _image; //stores image by value

public:
  ImageHolder()
  {
  }

  ImageHolder(ImageHolder&& source)
  :  _image(std::move(source._image))
  {
  }

  ImageHolder(const ImageHolder& origin)
  :  _image(source._image)
  {
  }
};

ImageHolder的move ctor中,我们简单的move构造了_image成员,所以它将默认初始化Image和3次交换。复制构造函数需要复制构造_image,所以所有数据都会被复制。

让我们考虑使用 bool 标志的解决方案。它有 2 个问题:

1)我们做不到。

ImageHolder(const ImageHolder& origin, bool copy = true)
:  _image(source._image)
{
  if(copy)
    //...
  else
    //...
}

如果 origin 声明为 const ImageHolder&,我们不能移动它,因为移动需要修改源对象 - 而我们不能修改 const 对象。

如果 origin 声明为非常量 ImageHolder&,我们将无法执行此操作:

ImageHolder new_holder(ImageHolder(image)); //parameter is a const reference

2) 在构造函数体中,成员已经被构造。

当我们到达此代码时:

if(copy)
  //...
else
  //...

_image 已经构造(更准确地说:复制构造),这意味着您已经复制了所有数据(因此没有必要移动任何东西)。

所以,是的,一切都与性能有关。如果您认为,您可以将 CPU 时间浪费在不必要地复制数百万字节的数据上...毕竟,这仅与性能有关。

移动构造函数是为您隐式编写的(除非您阻止它)。

在某些情况下会自动为您调用移动构造函数,即使您在它们存在之前编写了代码。

仅移动类型可以与移动构造函数一起存在,并且它们会在编译时阻止复制操作并出错。

将某些内容标记为 'please move from this' 不需要第二个参数,可以完美转发。完美转发也只适用于右值。 (完美的转发是不完美的,顺便说一句)

移动分配不适用于您的模式。

右值引用在 move/assign 之外的上下文中很有用。

老实说,将 C++11 移动和右值引用与您的提案进行比较就像在问为什么 Telsa 比车轮坏了的三轮车更好。破三轮车更便宜,我给。