vault backup: 2022-06-09 14:20:26
Affected files: 02. PARA/03. Resources(資源)/C++17/rvalue.md
This commit is contained in:
@@ -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的情況下,訊息就變成:
|
||||||
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user