详解C++中对构造函数和赋值运算符的复制和移动操作
复制构造函数和复制赋值运算符 Point a,b; ... a = b; 导致 b 的值被复制到 a 中。 TextFile a,b; a.Open( "FILE1.DAT" ); b.Open( "FILE2.DAT" ); b = a; 前面的代码可能表示“将 FILE1.DAT 的内容复制到 FILE2.DAT”,也可能表示“忽略 FILE2.DAT 并使 b 成为 FILE1.DAT 的另一个句柄”。 您必须将适当的复制语义附加到每个类,如下所示。 // spec1_copying_class_objects.cpp class Window { public: Window( const Window& ); // Declare copy constructor. // ... }; int main() { } 说明: 移动构造函数和移动赋值运算符 // MemoryBlock.h #pragma once #include <iostream> #include <algorithm> class MemoryBlock { public: // Simple constructor that initializes the resource. explicit MemoryBlock(size_t length) : _length(length),_data(new int[length]) { std::cout << "In MemoryBlock(size_t). length = " << _length << "." << std::endl; } // Destructor. ~MemoryBlock() { std::cout << "In ~MemoryBlock(). length = " << _length << "."; if (_data != nullptr) { std::cout << " Deleting resource."; // Delete the resource. delete[] _data; } std::cout << std::endl; } // Copy constructor. MemoryBlock(const MemoryBlock& other) : _length(other._length),_data(new int[other._length]) { std::cout << "In MemoryBlock(const MemoryBlock&). length = " << other._length << ". Copying resource." << std::endl; std::copy(other._data,other._data + _length,_data); } // Copy assignment operator. MemoryBlock& operator=(const MemoryBlock& other) { std::cout << "In operator=(const MemoryBlock&). length = " << other._length << ". Copying resource." << std::endl; if (this != &other) { // Free the existing resource. delete[] _data; _length = other._length; _data = new int[_length]; std::copy(other._data,_data); } return *this; } // Retrieves the length of the data resource. size_t Length() const { return _length; } private: size_t _length; // The length of the resource. int* _data; // The resource. }; 以下过程介绍如何为示例 C++ 类编写移动构造函数和移动赋值运算符。 MemoryBlock(MemoryBlock&& other) : _data(nullptr),_length(0) { } 在移动构造函数中,将源对象中的类数据成员添加到要构造的对象: _data = other._data; _length = other._length; 将源对象的数据成员分配给默认值。 这样可以防止析构函数多次释放资源(如内存): other._data = nullptr; other._length = 0; 为 C++ 类创建移动赋值运算符 MemoryBlock& operator=(MemoryBlock&& other) { } 在移动赋值运算符中,如果尝试将对象赋给自身,则添加不执行运算的条件语句。 if (this != &other) { } 在条件语句中,从要将其赋值的对象中释放所有资源(如内存)。 // Free the existing resource. delete[] _data; 执行第一个过程中的步骤 2 和步骤 3 以将数据成员从源对象转移到要构造的对象: // Copy the data pointer and its length from the // source object. _data = other._data; _length = other._length; // Release the data pointer from the source object so that // the destructor does not free the memory multiple times. other._data = nullptr; other._length = 0; 返回对当前对象的引用,如以下示例所示: return *this; 以下示例显示了 MemoryBlock 类的完整移动构造函数和移动赋值运算符: // Move constructor. MemoryBlock(MemoryBlock&& other) : _data(nullptr),_length(0) { std::cout << "In MemoryBlock(MemoryBlock&&). length = " << other._length << ". Moving resource." << std::endl; // Copy the data pointer and its length from the // source object. _data = other._data; _length = other._length; // Release the data pointer from the source object so that // the destructor does not free the memory multiple times. other._data = nullptr; other._length = 0; } // Move assignment operator. MemoryBlock& operator=(MemoryBlock&& other) { std::cout << "In operator=(MemoryBlock&&). length = " << other._length << "." << std::endl; if (this != &other) { // Free the existing resource. delete[] _data; // Copy the data pointer and its length from the // source object. _data = other._data; _length = other._length; // Release the data pointer from the source object so that // the destructor does not free the memory multiple times. other._data = nullptr; other._length = 0; } return *this; } 以下示例演示移动语义如何能提高应用程序的性能。此示例将两个元素添加到一个矢量对象,然后在两个现有元素之间插入一个新元素。在 Visual C++ 2010 中,vector 类使用移动语义,通过移动矢量元素(而非复制它们)来高效地执行插入操作。 // rvalue-references-move-semantics.cpp // compile with: /EHsc #include "MemoryBlock.h" #include <vector> using namespace std; int main() { // Create a vector object and add a few elements to it. vector<MemoryBlock> v; v.push_back(MemoryBlock(25)); v.push_back(MemoryBlock(75)); // Insert a new element into the second position of the vector. v.insert(v.begin() + 1,MemoryBlock(50)); } 该示例产生下面的输出: In MemoryBlock(size_t). length = 25. In MemoryBlock(MemoryBlock&&). length = 25. Moving resource. In ~MemoryBlock(). length = 0. In MemoryBlock(size_t). length = 75. In MemoryBlock(MemoryBlock&&). length = 25. Moving resource. In ~MemoryBlock(). length = 0. In MemoryBlock(MemoryBlock&&). length = 75. Moving resource. In ~MemoryBlock(). length = 0. In MemoryBlock(size_t). length = 50. In MemoryBlock(MemoryBlock&&). length = 50. Moving resource. In MemoryBlock(MemoryBlock&&). length = 50. Moving resource. In operator=(MemoryBlock&&). length = 75. In operator=(MemoryBlock&&). length = 50. In ~MemoryBlock(). length = 0. In ~MemoryBlock(). length = 0. In ~MemoryBlock(). length = 25. Deleting resource. In ~MemoryBlock(). length = 50. Deleting resource. In ~MemoryBlock(). length = 75. Deleting resource. 使用移动语义的此示例版本比不使用移动语义的版本更高效,因为前者执行的复制、内存分配和内存释放操作更少。 // Move constructor. MemoryBlock(MemoryBlock&& other) : _data(nullptr),_length(0) { *this = std::move(other); } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |