Expert C++
上QQ阅读APP看书,第一时间看更新

Moving objects

Temporary objects are everywhere in code. Most of the time, they are required to make the code work as expected. For example, when we add two objects together, a temporary object is created to hold the return value of operator+:

Warehouse small;
Warehouse mid;
// ... some data inserted into the small and mid objects
Warehouse large{small + mid}; // operator+(small, mid)

Let's take a look at the implementation of the global operator+() for Warehouse objects:

// considering declared as friend in the Warehouse class
Warehouse operator+(const Warehouse& a, const Warehouse& b) {
Warehouse sum; // temporary
sum.size_ = a.size_ + b.size_;
sum.capacity_ = a.capacity_ + b.capacity_;
sum.products_ = new Product[sum.capacity_];
for (int ix = 0; ix < a.size_; ++ix) { sum.products_[ix] = a.products_[ix]; }
for (int ix = 0; ix < b.size_; ++ix) { sum.products_[a.size_ + ix] = b.products_[ix]; }
return sum;
}

The preceding implementation declares a temporary object and returns it after filling it with necessary data. The call in the previous example could be translated into the following:

Warehouse small;
Warehouse mid;
// ... some data inserted into the small and mid objects
Warehouse tmp{operator+(small, mid)};
Warehouse large;
Warehouse_copy_constructor(large, tmp);
__destroy_temporary(tmp);

The move semantics, which was introduced in C++11, allows us to skip the temporary creation by moving the return value into the Warehouse object. To do so, we should declare a move constructor for the Warehouse, which can distinguish between temporaries and treat them efficiently:

class Warehouse {
public:
Warehouse(); // default constructor
Warehouse(const Warehouse&); // copy constructor
Warehouse(Warehouse&&); // move constructor
// code omitted for brevity
};

The parameter of the move constructor is an rvalue reference (&&).