vault backup: 2022-06-09 14:50:27
Affected files: .obsidian/workspace 02. PARA/03. Resources(資源)/C++17/rvalue.md 02. PARA/03. Resources(資源)/C++17/智慧指標.md
This commit is contained in:
12
.obsidian/workspace
vendored
12
.obsidian/workspace
vendored
@@ -10,7 +10,7 @@
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "02. PARA/03. Resources(資源)/C++17/智慧指標.md",
|
||||
"file": "02. PARA/03. Resources(資源)/C++17/rvalue.md",
|
||||
"mode": "source",
|
||||
"source": true
|
||||
}
|
||||
@@ -23,7 +23,7 @@
|
||||
"state": {
|
||||
"type": "outline",
|
||||
"state": {
|
||||
"file": "02. PARA/03. Resources(資源)/C++17/智慧指標.md"
|
||||
"file": "02. PARA/03. Resources(資源)/C++17/rvalue.md"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@
|
||||
"state": {
|
||||
"type": "backlink",
|
||||
"state": {
|
||||
"file": "02. PARA/03. Resources(資源)/C++17/智慧指標.md",
|
||||
"file": "02. PARA/03. Resources(資源)/C++17/rvalue.md",
|
||||
"collapseAll": true,
|
||||
"extraContext": true,
|
||||
"sortOrder": "alphabetical",
|
||||
@@ -125,15 +125,15 @@
|
||||
},
|
||||
"active": "94f0e8a81af6c9e2",
|
||||
"lastOpenFiles": [
|
||||
"02. PARA/03. Resources(資源)/C++17/智慧指標.md",
|
||||
"02. PARA/03. Resources(資源)/C++17/rvalue.md",
|
||||
"02. PARA/03. Resources(資源)/C++17/move operator.md",
|
||||
"02. PARA/03. Resources(資源)/C++17/智慧指標.md",
|
||||
"00. TOP/01. TODO.md",
|
||||
"02. PARA/03. Resources(資源)/git/submodule.md",
|
||||
"02. PARA/03. Resources(資源)/git.md",
|
||||
"02. PARA/01. Project(專案)/008. Sentinel.md",
|
||||
"02. PARA/03. Resources(資源)/C++17/lvalue.md",
|
||||
"02. PARA/03. Resources(資源)/FFMPEG/01. Setup.md",
|
||||
"02. PARA/03. Resources(資源)/FFMPEG/00. Introduction.md",
|
||||
"02. PARA/03. Resources(資源)/FFMpeg.md"
|
||||
"02. PARA/03. Resources(資源)/FFMPEG/00. Introduction.md"
|
||||
]
|
||||
}
|
||||
@@ -17,8 +17,8 @@ int b = 5;
|
||||
int& c = a + b;
|
||||
```
|
||||
|
||||
因為`a+b`是一個rvalue(臨時的值,沒辦法取址),所以無法參考。
|
||||
但是可以用`&&`來參考rvalue。例如:
|
||||
因為`a+b`是一個 rvalue(臨時的值,沒辦法取址),所以無法參考。
|
||||
但是可以用`&&`來參考 rvalue。例如:
|
||||
```cpp
|
||||
int a = 10;
|
||||
int b = 5;
|
||||
@@ -33,10 +33,10 @@ int r = a + b;
|
||||
int& c = r;
|
||||
```
|
||||
|
||||
了解rvalue reference之後,就可以實作類別的 move constructor 跟move assignment operator。這可以減少複製的成本。
|
||||
了解 rvalue reference 之後,就可以實作類別的 move constructor 跟 move assignment operator。這可以減少複製的成本。
|
||||
|
||||
## Move constructor
|
||||
假設我們有一個class叫BigBuffer,定義如下:
|
||||
假設我們有一個 class 叫 BigBuffer,定義如下:
|
||||
```cpp
|
||||
class BigBuffer {
|
||||
public:
|
||||
@@ -72,7 +72,7 @@ private:
|
||||
};
|
||||
```
|
||||
|
||||
這個class的特色就是每一次使用都會佔用100MB的記憶體空間,想像下面的程式的動作:
|
||||
這個 class 的特色就是每一次使用都會佔用100MB的記憶體空間,想像下面的程式的動作:
|
||||
```cpp
|
||||
BigBuffer buf1;
|
||||
// Do something with buf1
|
||||
@@ -87,7 +87,7 @@ BigBuffer copy constructor, copy 104857600Bytes // copy buf1 to buf2
|
||||
...
|
||||
```
|
||||
|
||||
這會先產生buf1,然後把buf1 copy給buf2。如果我們想要省下copy的成本,這時候 Move constructor 就可以派上用場了。
|
||||
這會先產生 buf1,然後把 buf1 copy 給 buf2。如果我們想要省下 copy 的成本,這時候 Move constructor 就可以派上用場了。
|
||||
幫 BigBuffer 加一個 Move constructor:
|
||||
```cpp
|
||||
class BigBuffer {
|
||||
@@ -106,9 +106,9 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
這個 move constructor 的參數就是一個 rvalue reference,我們把來源的 bufferSize 跟 buffer指標「移到」我們這邊,而不是完整的複製一份。在轉移之後呢,當然也要把來源清空,讓轉移更加明確。
|
||||
這個 move constructor 的參數就是一個 rvalue reference,我們把來源的 bufferSize 跟 buffer 指標「移到」我們這邊,而不是完整的複製一份。在轉移之後呢,當然也要把來源清空,讓轉移更加明確。
|
||||
|
||||
有了 Move assignment operator 之後,在執行一次原本的程式,你會發現訊息......沒有變,還是一樣呼叫 copy constructor 來複製了100MB的buffer,這時我們需要明確的告訴 compiler 我們要「移動」物件,而不是複製它,把原本的程式改為:
|
||||
有了 Move assignment operator 之後,在執行一次原本的程式,你會發現訊息......沒有變,還是一樣呼叫 copy constructor 來複製了100MB 的 buffer,這時我們需要明確的告訴 compiler 我們要「移動」物件,而不是複製它,把原本的程式改為:
|
||||
```cpp
|
||||
BigBuffer buf1;
|
||||
// Do something with buf1
|
||||
@@ -123,7 +123,7 @@ BigBuffer move constructor // move buf1 to buf2, buf1 has nullptr now
|
||||
...
|
||||
```
|
||||
|
||||
另外一個情形也可以受益於此,假如我們有個function會產生 BigBuffer,如下:
|
||||
另外一個情形也可以受益於此,假如我們有個 function 會產生 `BigBuffer`,如下:
|
||||
```cpp
|
||||
BigBuffer BigBufferCreator() {
|
||||
std::cout << "BigBufferCreator: Create a BigBuffer!\n";
|
||||
@@ -136,7 +136,7 @@ BigBuffer BigBufferCreator() {
|
||||
BigBuffer b = BigBufferCreator(); // copy tempb to b
|
||||
```
|
||||
|
||||
在沒有Move constructor的情況下,上面的程式會先產生一個 tempb,然後複製給 b,訊息:
|
||||
在沒有 Move constructor 的情況下,上面的程式會先產生一個 `tempb`,然後複製給 `b`,訊息:
|
||||
```
|
||||
BigBufferCreator: Create a BigBuffer!
|
||||
BigBuffer constructor
|
||||
@@ -145,7 +145,7 @@ BigBuffer copy constructor, copy 104857600Bytes // Copy 100MB!
|
||||
...
|
||||
```
|
||||
|
||||
在有Move constructor的情況下,訊息就變成:
|
||||
在有 Move constructor 的情況下,訊息就變成:
|
||||
```
|
||||
BigBufferCreator: Create a BigBuffer!
|
||||
BigBuffer constructor
|
||||
@@ -155,10 +155,10 @@ BigBuffer destructor
|
||||
BigBuffer destructor
|
||||
```
|
||||
|
||||
因為 `BigBufferCreator()` 產生的就是一個 BigBuffer rvalue,所以 compiler會使用 move constructor(`BigBuffer(BigBuffer&& src)`) 而不是 copy constructor。
|
||||
因為 `BigBufferCreator()` 產生的就是一個 `BigBuffer` rvalue,所以 compiler 會使用 move constructor(`BigBuffer(BigBuffer&& src)`) 而不是 copy constructor。
|
||||
|
||||
## Move assignment operator(`=`)
|
||||
Move assignment operator 的行為跟 move constructor 是一樣的,幫 BigBuffer 加入 move assignment operator:
|
||||
Move assignment operator 的行為跟 move constructor 是一樣的,幫 `BigBuffer` 加入 move assignment operator:
|
||||
```cpp
|
||||
class BigBuffer {
|
||||
public:
|
||||
@@ -196,8 +196,15 @@ BigBuffer b1, b2;
|
||||
b2 = std::move(b1);
|
||||
```
|
||||
|
||||
這樣就可以了。
|
||||
這樣就可以了。訊息:
|
||||
```
|
||||
BigBuffer constructor
|
||||
BigBuffer constructor
|
||||
BigBuffer move operator // Use MOVE!
|
||||
```
|
||||
|
||||
## 參考
|
||||
- [Value categories - cppreference.com](https://en.cppreference.com/w/cpp/language/value_category)
|
||||
- [rvalue 參考](https://openhome.cc/Gossip/CppGossip/RvalueReference.html)
|
||||
- [rvalue 參考](https://openhome.cc/Gossip/CppGossip/RvalueReference.html)
|
||||
- [Move constructors - cppreference.com](https://en.cppreference.com/w/cpp/language/move_constructor)
|
||||
- [Move assignment operator - cppreference.com](https://en.cppreference.com/w/cpp/language/move_assignment)
|
||||
@@ -68,7 +68,7 @@ auto ptr1 = std::make_unique<int>(5);
|
||||
auto anotherPtr = std::move(ptr1);
|
||||
```
|
||||
|
||||
ptr1原本所管理的指標會轉移給 anotherPtr,
|
||||
ptr1原本所管理的指標會轉移給 anotherPtr,ptr1 會變成 nullptr。
|
||||
|
||||
## shared_ptr
|
||||
建立一個 `shared_ptr` 是使用[`std::make_shared()`](https://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared):
|
||||
|
||||
Reference in New Issue
Block a user