我有一个用RAII编写的Array类(为了这个例子,超级简化):
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
将包含不存在的数据。
那么将数据所有权从一个对象“移动”到另一个对象的最佳方法是什么?
答案 0 :(得分:5)
您想要的是为阵列类移动构造或移动分配,这样可以节省多余的副本。此外,它将帮助您使用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);
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_size
和m_data
公开是一个坏主意,因为他们被捆绑在一起并且你不希望别人搞砸他们。我也会在元素类型上模拟该类,即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
}
答案 1 :(得分:2)
如果你坚持你的示例格式,那么你会遗漏几件事。你需要确保临时数组不会破坏非临时数组重用的内存。
~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及更高版本中,您可以创建一个移动构造函数并从函数中返回值:
Array(Array &&temp) {
do your move here
}
Array function() {
Array temp(...);
return temp;
}
还有其他方法。