diff --git a/02. PARA/03. Resources(資源)/C++17/rvalue.md b/02. PARA/03. Resources(資源)/C++17/rvalue.md index 341acb3..1be6fa8 100644 --- a/02. PARA/03. Resources(資源)/C++17/rvalue.md +++ b/02. PARA/03. Resources(資源)/C++17/rvalue.md @@ -35,7 +35,7 @@ int& c = r; 了解rvalue reference之後,就可以實作類別的 move constructor 跟move assignment operator。 -## Move assignment operator +## Move constructor 假設我們有一個class叫BigBuffer,定義如下: ```cpp class BigBuffer { @@ -82,34 +82,32 @@ BigBuffer buf2 = buf1; 執行訊息: ``` -BigBuffer constructor -BigBuffer copy constructor, copy 104857600Bytes -BigBuffer destructor -BigBuffer destructor +BigBuffer constructor // create buf1 +BigBuffer copy constructor, copy 104857600Bytes // copy buf1 to buf2 +... ``` -這會先產生buf1,然後把buf1 copy給buf2。如果我們想要省下copy的成本,這時候 Move assignment operator(就是 `=`)就可以派上用場了。 -幫 BigBuffer 加一個 Move assignment operator: +這會先產生buf1,然後把buf1 copy給buf2。如果我們想要省下copy的成本,這時候 Move constructor 就可以派上用場了。 +幫 BigBuffer 加一個 Move constructor: ```cpp class BigBuffer { public: ... - BigBuffer& operator=(BigBuffer&& src) noexcept { - std::cout << "BigBuffer move operator\n"; + BigBuffer(BigBuffer&& src) noexcept { + std::cout << "BigBuffer move constructor\n"; bufferSize = src.bufferSize; buffer = std::move(src.buffer); - + src.buffer.reset(); src.bufferSize = 0; - return *this; } ... ``` -這個 Move assignment operator 的參數就是一個 rvalue reference,我們把來源的 bufferSize 跟 buffer指標「移到」我們這邊,而不是完整的複製一份。在轉移之後呢,當然也要把來源清空,讓轉移更加明確。 +這個 move constructor 的參數就是一個 rvalue reference,我們把來源的 bufferSize 跟 buffer指標「移到」我們這邊,而不是完整的複製一份。在轉移之後呢,當然也要把來源清空,讓轉移更加明確。 -有了 Move assignment operator 之後,在執行一次原本的程式,你會發現訊息......沒有變,還是一樣呼叫 copy assignment operator 來複製了100MB的buffer,這時我們需要明確的告訴 compiler 我們要「移動」物件,而不是複製它,把原本的程式改為: +有了 Move assignment operator 之後,在執行一次原本的程式,你會發現訊息......沒有變,還是一樣呼叫 copy constructor 來複製了100MB的buffer,這時我們需要明確的告訴 compiler 我們要「移動」物件,而不是複製它,把原本的程式改為: ```cpp BigBuffer buf1; // Do something with buf1 @@ -119,6 +117,35 @@ BigBuffer buf2 = std::move(buf1); 我們用 `std::move()` 來「移動」物件,這時輸出變成 ``` +BigBuffer constructor // create buf1 +BigBuffer move constructor // move buf1 to buf2, buf1 has nullptr now +... +``` + +另外一個情形也可以受益於此,假如我們有個function會產生 BigBuffer,如下: +```cpp +BigBuffer BigBufferCreator() { + std::cout << "BigBufferCreator: Create a BigBuffer!\n"; + BigBuffer tempb; + // do something + std::cout << "BigBufferCreator: return\n"; + return tempb; +} + +BigBuffer b = BigBufferCreator(); // copy tempb to b +``` + +在沒有Move constructor的情況下,上面的程式會先產生一個 tempb,然後複製給 b,訊息: +``` +BigBufferCreator: Create a BigBuffer! +BigBuffer constructor +BigBufferCreator: return +BigBuffer copy constructor, copy 104857600Bytes +... +``` + +在有Move constructor的情況下,訊息就變成: +``` ```