如何将动态分配的数据从一个对象移动到另一个对象?
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_size
和 m_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
}
我有一个用 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_size
和 m_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
}