vault backup: 2022-06-09 14:20:26

Affected files:
02. PARA/03. Resources(資源)/C++17/rvalue.md
This commit is contained in:
2022-06-09 14:20:26 +08:00
parent fa039f4641
commit bf8ebd3a93

View File

@@ -35,7 +35,7 @@ int& c = r;
了解rvalue reference之後就可以實作類別的 move constructor 跟move assignment operator。 了解rvalue reference之後就可以實作類別的 move constructor 跟move assignment operator。
## Move assignment operator ## Move constructor
假設我們有一個class叫BigBuffer定義如下 假設我們有一個class叫BigBuffer定義如下
```cpp ```cpp
class BigBuffer { class BigBuffer {
@@ -82,34 +82,32 @@ BigBuffer buf2 = buf1;
執行訊息: 執行訊息:
``` ```
BigBuffer constructor BigBuffer constructor // create buf1
BigBuffer copy constructor, copy 104857600Bytes BigBuffer copy constructor, copy 104857600Bytes // copy buf1 to buf2
BigBuffer destructor ...
BigBuffer destructor
``` ```
這會先產生buf1然後把buf1 copy給buf2。如果我們想要省下copy的成本這時候 Move assignment operator就是 `=`就可以派上用場了。 這會先產生buf1然後把buf1 copy給buf2。如果我們想要省下copy的成本這時候 Move constructor 就可以派上用場了。
幫 BigBuffer 加一個 Move assignment operator 幫 BigBuffer 加一個 Move constructor
```cpp ```cpp
class BigBuffer { class BigBuffer {
public: public:
... ...
BigBuffer& operator=(BigBuffer&& src) noexcept { BigBuffer(BigBuffer&& src) noexcept {
std::cout << "BigBuffer move operator\n"; std::cout << "BigBuffer move constructor\n";
bufferSize = src.bufferSize; bufferSize = src.bufferSize;
buffer = std::move(src.buffer); buffer = std::move(src.buffer);
src.buffer.reset(); src.buffer.reset();
src.bufferSize = 0; 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 ```cpp
BigBuffer buf1; BigBuffer buf1;
// Do something with buf1 // Do something with buf1
@@ -119,6 +117,35 @@ BigBuffer buf2 = std::move(buf1);
我們用 `std::move()` 來「移動」物件,這時輸出變成 我們用 `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的情況下訊息就變成
```
``` ```