移動建構函式
假設我們有這段程式碼。
class A {
public:
int a;
int b;
A(const A &other) {
this->a = other.a;
this->b = other.b;
}
};
要建立一個複製建構函式,即建立一個複製物件並建立一個新物件的函式,我們通常會選擇上面顯示的語法,我們將有一個 A 的建構函式,它引用另一個型別為 A 的物件,我們將在方法內手動複製物件。
或者,我們可以編寫 A(const A &) = default;
,它會自動複製所有成員,並使用其複製建構函式。
但是,要建立移動建構函式,我們將使用右值引用而不是左值引用,就像這裡一樣。
class Wallet {
public:
int nrOfDollars;
Wallet() = default; //default ctor
Wallet(Wallet &&other) {
this->nrOfDollars = other.nrOfDollars;
other.nrOfDollars = 0;
}
};
請注意我們將舊值設定為 zero
。預設移動建構函式(Wallet(Wallet&&) = default;
)複製 nrOfDollars
的值,因為它是 POD。
由於移動語義被設計為允許從原始例項竊取狀態,因此考慮在此竊取之後原始例項應該是什麼樣子是很重要的。在這種情況下,如果我們不將值更改為零,我們就會將美元數量增加一倍。
Wallet a;
a.nrOfDollars = 1;
Wallet b (std::move(a)); //calling B(B&& other);
std::cout << a.nrOfDollars << std::endl; //0
std::cout << b.nrOfDollars << std::endl; //1
因此,我們移動構造了一箇舊物件。
雖然上面是一個簡單的例子,但它顯示了移動建構函式的目的。它在更復雜的情況下變得更有用,例如涉及資源管理時。
// Manages operations involving a specified type.
// Owns a helper on the heap, and one in its memory (presumably on the stack).
// Both helpers are DefaultConstructible, CopyConstructible, and MoveConstructible.
template<typename T,
template<typename> typename HeapHelper,
template<typename> typename StackHelper>
class OperationsManager {
using MyType = OperationsManager<T, HeapHelper, StackHelper>;
HeapHelper<T>* h_helper;
StackHelper<T> s_helper;
// ...
public:
// Default constructor & Rule of Five.
OperationsManager() : h_helper(new HeapHelper<T>) {}
OperationsManager(const MyType& other)
: h_helper(new HeapHelper<T>(*other.h_helper)), s_helper(other.s_helper) {}
MyType& operator=(MyType copy) {
swap(*this, copy);
return *this;
}
~OperationsManager() {
if (h_helper) { delete h_helper; }
}
// Move constructor (without swap()).
// Takes other's HeapHelper<T>*.
// Takes other's StackHelper<T>, by forcing the use of StackHelper<T>'s move constructor.
// Replaces other's HeapHelper<T>* with nullptr, to keep other from deleting our shiny
// new helper when it's destroyed.
OperationsManager(MyType&& other) noexcept
: h_helper(other.h_helper),
s_helper(std::move(other.s_helper)) {
other.h_helper = nullptr;
}
// Move constructor (with swap()).
// Places our members in the condition we want other's to be in, then switches members
// with other.
// OperationsManager(MyType&& other) noexcept : h_helper(nullptr) {
// swap(*this, other);
// }
// Copy/move helper.
friend void swap(MyType& left, MyType& right) noexcept {
std::swap(left.h_helper, right.h_helper);
std::swap(left.s_helper, right.s_helper);
}
};