vault backup: 2022-06-06 11:04:20

Affected files:
02. PARA/03. Resources(資源)/C++17/智慧指標.md
This commit is contained in:
2022-06-06 11:04:20 +08:00
parent a779779c22
commit 85fe2a26e4

View File

@@ -1,8 +1,8 @@
unique_ptr與shared_ptr都是智慧指標箱對於原本的raw pointer智慧指標使用起來更方便也不用擔心delete的問題。 unique_ptr與shared_ptr都是智慧指標箱對於原本的raw pointer智慧指標使用起來更方便也不用擔心delete的問題。
## unique_ptr ## unique_ptr
unique_ptr的特點是它保證在一個時間內只會有一個指標的擁有者也就是這個指標不能被複製跟移動當unique_ptr離開它的scope時候它所擁有的pointer也隨之被delete。這讓你不用擔心memory leak的問題。 `unique_ptr`的特點是,它保證在一個時間內,只會有一個指標的擁有者,也就是這個指標不能被複製跟移動,當`unique_ptr`離開它的scope時候它所擁有的pointer也隨之被delete。這讓你不用擔心memory leak的問題。
原本分配記憶體的方法假設我們有一個class叫BigBuffer 原本分配記憶體的方法假設我們有一個class叫`BigBuffer`
```cpp ```cpp
BigBuffer* bigBuf = new BigBuffer(bufferSize); BigBuffer* bigBuf = new BigBuffer(bufferSize);
@@ -11,23 +11,23 @@ BigBuffer* bigBuf = new BigBuffer(bufferSize);
delete bigBuf; delete bigBuf;
``` ```
用unique_ptr `unique_ptr`
```cpp ```cpp
auto bigBuf = std::make_unique<BigBuffer>(bufferSize); auto bigBuf = std::make_unique<BigBuffer>(bufferSize);
// Use buffer here // Use buffer here
// bigBuf will be released when exiting scope // bigBuf will be released when exiting scope
``` ```
我們統一用`std::make_unique<>`這個template function來建立unique_ptr角括號<>裡面要帶入你要建立的型別,後面的括號()就是型別的constructor使用起來跟new是一樣的。 我們統一用`std::make_unique<>`這個template function來建立`unique_ptr`,角括號`<>`裡面要帶入你要建立的型別,後面的括號`()`就是型別的constructor使用起來跟new是一樣的。
因為`std::make_unique<>`裡面已經有表明型別了所以變數就用auto就可以了不用再寫一次型別。 因為`std::make_unique<>`裡面已經有表明型別了,所以變數就用`auto`就可以了,不用再寫一次型別。
一旦unique_ptr建立之後使用起來就跟一般指標沒有兩樣都是用`->`來操作:`bigBuf->setXXX()` or `bigBuf->getXXX()` 一旦`unique_ptr`建立之後,使用起來就跟一般指標沒有兩樣,都是用`->`來操作:`bigBuf->setXXX()` or `bigBuf->getXXX()`
但是別忘記unique_ptr本身還是一個local variable所以我們可以用`.`來操作unique_ptr例如我們可以用`.reset()`重新配一個指標: 但是別忘記`unique_ptr`本身還是一個local variable所以我們可以用`.`來操作`unique_ptr`,例如我們可以用`.reset()`重新配一個指標:
```cpp ```cpp
bigBuf.reset(std::make_unique<BigBuffer>(bufferSizeLarger)); bigBuf.reset(std::make_unique<BigBuffer>(bufferSizeLarger));
``` ```
這時候舊指標會自動delete然後指向新的指標如果記憶體分配有成功的話或者指向nullptr記憶體分配失敗 這時候舊指標會自動delete然後指向新的指標如果記憶體分配有成功的話或者指向`nullptr`(記憶體分配失敗)。
如果單純想要釋放指標那就單純的reset就好。 如果單純想要釋放指標,那就單純的呼叫`reset()`就好。
```cpp ```cpp
bigBuf.reset(); // Now I'm nullptr bigBuf.reset(); // Now I'm nullptr
``` ```
@@ -42,12 +42,20 @@ auto intArray = std::make_unique<int[]>(1024);
intArray[5] = 555; intArray[5] = 555;
``` ```
不過對於陣列的操作現在更建議使用std::array。 不過對於陣列的操作現在更建議使用`std::array`
如果有什麼特殊原因讓你決定不再讓unique_ptr幫你管理指標,可以用`release`來讓出指標: 如果有什麼特殊原因讓你決定不再讓`unique_ptr`幫你管理指標,可以用`release()`來讓出指標:
```cpp ```cpp
auto intArray = std::make_unique<int[]>(1024); auto intArray = std::make_unique<int[]>(1024);
int* intArrayRaw = int* intArrayRaw = intArray.release(); // Now I don't care anymore
```
但是這時候呼叫`delete[]`(或`delete`)的責任又回到你身上了。所以千萬不要把`release()``reset()`搞混了。
`unique_ptr`不能被複製跟移動,所以下列的寫法都編不過:
```cpp
std::unique_ptr<int> ptr2(ptr1); // Error
std::unique_ptr<int> ptr2 = ptr1; // Error
``` ```
## shared_ptr ## shared_ptr