移动构造函数相对于复制构造函数有什么优势,它可以使用bool来表示是复制还是移动?

时间:2015-03-20 21:11:14

标签: c++ c++11 move

为什么我们需要在C ++中使用移动构造函数/赋值运算符:

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

或者我错过了什么?

2 个答案:

答案 0 :(得分:1)

C ++中的类可以代表任何东西。文件,线程,字符串,3d对象 - 所有这些都可以表示为某个类的实例。这些对象可能包含大量内部数据。请考虑以下示例:

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&amp; img)使用存储在img中的数据初始化图像,但它首先完全复制该数据(考虑使用全高清分辨率的32bpp图像 - InitWithDeepCopyOf()将复制8.3MB数据!)。< / p>

在我们的计划中,我们有另一个班级:

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的移动ctor中,我们简单地移动了构造_image成员,因此它将采用Image和3个交换的默认初始化。复制构造函数需要复制构造_image,因此所有数据都将被复制。

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

1)我们不能正确地做到这一点。

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

如果将origin声明为const ImageHolder&amp ;,我们就无法移动它,因为移动需要修改源对象 - 我们无法修改const对象。

如果origin被声明为非const ImageHolder&amp;,我们将无法执行此操作:

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

2)在构造者的身体中,成员已经构建。

当我们达到此代码时:

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

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

所以,是的,这完全取决于性能。如果你认为,你可以将CPU时间浪费在不必要的数百兆字节数据上......毕竟,这只是关于性能的。

答案 1 :(得分:1)

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

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

只有移动构造函数可以存在移动类型,并且它们在编译时阻止复制操作并带有错误。

将某些内容标记为&#39;请从此处移除&#39;不需要第二个参数,完成转发工作。完美转发也适用于右值。 (完美的转发是不完美的,顺便说一句)

移动作业不会很好地适应您的模式。

rvalue ref在move / assign之外的上下文中很有用。

老实说,将C ++ 11 move和rvalue refs与你的提议进行比较就好像问为什么Telsa比带有破碎轮子的三轮车更好。破碎的三轮车更便宜,我会批准它。