I have an Array class written with RAII in mind (super simplified for the purpose of this example):
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;
};
Then I have a function that takes a reference to an Array and does some operations on it. I use a temporary Array temp
to perform the processing, because for several reasons I can't work directly with the reference. Once done, I would like to transfer the data from the temporary Array to the real one:
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;
}
The obvious problem is that temp
goes out of scope at the end of the function: its destructor is triggered, which in turn deletes the memory. This way array
would contain non-existent data.
So what is the best way to "move" the ownership of data from an object to another?
What you want is move construction or move assignment for your array class, which saves you redundant copies. Also, it will help you to use std::unique_ptr
which will take care of move semantics for allocated memory for you, so that you don't need to do any memory allocation directly, yourself. You will still need to pull up your sleeves and follow the "rule of zero/three/five", which in our case is the rule of five (copy & move constructor, copy & move assignment operator, destructor).
So, try:
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;
};
(Actually, it's a bad idea to have m_size
and m_data
public, since they're tied together and you don't want people messing with them. I would also template that class on the element type, i.e. T
instead of int
and use Array<int>
)
Now you can implement your function in a very straightforward manner:
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
}