如何将动态分配的数据从一个对象移动到另一个对象?

How do I move dynamically allocated data from an object to another?

我有一个用 RAII 编写的数组 class(为了这个例子的目的超级简化):

struct Array
{
    Array(int size) {
        m_size = size;
        m_data = new int[m_size];
    }

    ~Array() {
        delete[] m_data;
    }

    int* m_data = nullptr;
    int  m_size = 0;
};

然后我有一个函数,它引用一个数组并对其进行一些操作。我使用临时数组 temp 来执行处理,因为出于多种原因我无法直接使用引用。完成后,我想将数据从临时数组传输到真实数组:

void function(Array& array)
{
    Array temp(array.m_size * 2);

    // do heavy processing on `temp`...

    array.m_size = temp.m_size;
    array.m_data = temp.m_data;
}

明显的问题是 temp 在函数结束时超出范围:它的析构函数被触发,进而删除内存。这样 array 将包含不存在的数据。

那么 "move" 将数据所有权从一个对象转移到另一个对象的最佳方式是什么?

如果您坚持使用示例格式,那么您会遗漏一些东西。您需要确保临时数组不会破坏 non-temp 数组重用的内存。

 ~Array() {
    if (md_data != nullptr) 
         delete [] m_data;
 }

并且函数需要做干净的移动

void function(Array& array)
{
    Array temp(array.m_size * 2);

    // do heavy processing on `temp`...

    array.m_size = temp.m_size;
    array.m_data = temp.m_data;
    temp.m_data = nullptr;
    temp.m_size = 0;
}

为了让它更像 C++,您可以做很多事情。即在数组中,您可以创建成员函数以从其他数组(或构造函数,或赋值运算符,...)移动数据

  void Array::move(Array &temp) {
      m_size = temp.m_size;
      temp.m_size = 0;
      m_data = temp.m_data;
      temp.m_data = 0;
  }

在 c++11 及更高版本中,您可以创建一个移动构造函数和 return 您的函数值:

 Array(Array &&temp) {
      do your move here
 }
 Array function() {
      Array temp(...);
      return temp;
 }

还有其他方法。

你想要的是为你的数组class移动构造或移动赋值,这样可以节省你的冗余副本。此外,它将帮助您使用 std::unique_ptr ,它将为您处理分配内存的移动语义,这样您就不需要自己直接进行任何内存分配。您仍然需要挽起袖子并遵循 "rule of zero/three/five",在我们的例子中是五法则(复制和移动构造函数、复制和移动赋值运算符、析构函数)。

所以,尝试:

class Array {
public:
    Array(size_t size) : m_size(size) {
        m_data = std::make_unique<int[]>(size);
    }

    Array(const Array& other) : Array(other.size) {
        std::copy_n(other.m_data.get(), other.m_size, m_data.get());
    }

    Array(Array&& other) : m_data(nullptr) {
        *this = other;
    } 

    Array& operator=(Array&& other) {
        std::swap(m_data, other.m_data);
        std::swap(m_size,other.m_size);
        return *this;
    }

    Array& operator=(const Array& other) {
        m_data = std::make_unique<int[]>(other.m_size);
        std::copy_n(other.m_data.get(), other.m_size, m_data.get());
        return *this;
    }

    ~Array() = default;

    std::unique_ptr<int[]>  m_data;
    size_t                  m_size;
};

(实际上,m_sizem_data public 是个坏主意,因为它们是捆绑在一起的,您不希望人们弄乱它们。我会也是在元素类型上 class 的模板,即 T 而不是 int 并使用 Array<int>)

现在您可以非常直接地实现您的功能:

void function(Array& array)
{
    Array temp { array }; // this uses the copy constructor

    // do heavy processing on `temp`...

    std::swap(array, temp); // a regular assignment would copy
}