淺談C++的智慧指標
阿新 • • 發佈:2020-08-15
C++11STL中新增了智慧指標,可以有效的防止記憶體洩露的問題,以下程式碼除特殊說明均在C++11下編譯。
標頭檔案
#include <memory>
shared_ptr 共享指標
共享指標可以方便的在不同函式中傳遞,並且在所有指標例項被銷燬時自動釋放空間。
shared_ptr通過引用計數來管理引用狀態,每次有新的引用時計數加1,有引用銷燬是計數減1,直到計數為0時自動釋放記憶體空間。
只要將new
運算子返回的指標p
交給一個shared_ptr
物件“託管”,就不必擔心在哪裡寫delete p
語句——實際上根本不需要編寫這條語句,託管p
的 shared_ptr
物件在消亡時會自動執行delete p
通過shared_ptr
的建構函式,傳入讓shared_ptr
託管的指標。
例如:
shared_ptr<int> p(new int);
在函式見傳遞shared_ptr
,示例程式碼:
#include <memory> #include <cstdio> using namespace std; struct node { int a, b, c; char e; }; int foo(shared_ptr<node> a) { // p2被傳入foo,a指向p2,引用計數加1,現在為3 return a->a + a->b; // foo函式結束,a被釋放,引用計數減1,現在為2 } // 聽說從main函式開始閱讀程式是一個好習慣 int main() { shared_ptr<int> p(new node); // p引用node物件的例項,引用計數現在為1 shared_ptr<int> p2 = p; // p2引用p,引用計數加1,現在為2 foo(p2); return 0; // main函式結束,p,p2被釋放,引用計數減2,現在為0 // 引用計數為0,自動釋放node的例項。 }
shared_ptr
可以通過get
成員函式獲取普通指標:
shared_ptr<int> p(new node);
printf("%p\n", p.get()); // 輸出p指向的例項的地址
shared_ptr
過載了->
和*
運算子,可以直接訪問目標物件:
shared_ptr<int> p(new node);
p->a = 5;
printf("%d\n", p->a);
printf("%d\n", (*p).a);
在C++17中從過載[]
運算子,用於訪問陣列:
shared_ptr<int[]> p(new int[105]); p[1] = 1; p[2] = 5; for (int i = 3; i <= 100; ++i) p[i] = i; int sum = 0; for (int i = 3; i <= 100; ++i) sum += p[i];
什麼,你想在C++11中用[]
運算子?那麼,有請下一位出場。
unique_ptr 單引用指標
unique_ptr一樣會自動釋放記憶體,但是隻能用一個unique_ptr
指向目標,其他的都會失效。
和Rust
中的所有權機制一樣。
在函式見傳遞unique_ptr
,示例程式碼:
#include <memory>
#include <cstdio>
using namespace std;
struct node {
int a, b, c;
char e;
};
unique_ptr<node> foo(unique_ptr<node> a) {
// p2被傳入foo,a獲取p2的所有權,p2失效。
a->a += a->b;
return a;
// foo函式結束,但是a被作為返回值返回,a擁有所有權。
}
void bar(unique_ptr<node> &a) {
// p2被傳入foo,a是p2的引用,p2擁有所有權。
a->a += a->c;
return;
// foo函式結束,a被銷燬,p2擁有所有權。
}
// 聽說從main函式開始閱讀程式是一個好習慣
int main() {
unique_ptr<int> p(new node); // p引用node物件的例項。
unique_ptr<int> p2 = p; // p2獲取p的所有權,現在p失效。
printf("%p\n", p.get()); // p已經失效,輸出0x00000000。
printf("%p\n", p1.get()); // 輸出p2指向的地址。
// 下面是兩種函式傳遞unique_ptr的方式
p2 = foo(p2); // foo函式返回a,p2重新取回所有權。
bar(p2);
return 0;
// main函式結束,p2被銷燬,記憶體自動釋放。
}
unique_ptr
可以通過get
成員函式獲取普通指標:
unique_ptr<int> p(new node);
printf("%p\n", p.get()); // 輸出p指向的例項的地址
unique_ptr
過載了->
和*
運算子,可以直接訪問目標物件:
unique_ptr<int> p(new node);
p->a = 5;
printf("%d\n", p->a);
printf("%d\n", (*p).a);
unique_ptr
從過載[]
運算子,用於訪問陣列:
shared_ptr<int[]> p(new int[105]);
p[1] = 1;
p[2] = 5;
for (int i = 3; i <= 100; ++i)
p[i] = i;
int sum = 0;
for (int i = 3; i <= 100; ++i)
sum += p[i];
weak_ptr 反向指標
不知道大家在之前看shared_ptr
時是否發現,如果有兩個物件相互引用,他們的引用計數永遠不會歸0,他們永遠不會被釋放,產生迴圈引用。
------------------- -------------------
| class A | | class B |
|-----------------| |-----------------|
|int x; | use each other |int y; |
|shared_ptr<B> b<--------------------->shared_ptr<A> a |
|-----------------| |-----------------|
這時就需要weak_ptr
出場了:
------------------- -------------------
| class A | | class B |
|-----------------| |-----------------|
|int x; |one direction use |int y; |
|shared_ptr<B> b---------------------->weak_ptr<A> a |
|-----------------| |-----------------|
這是因為weak_ptr
的引用不會被shared_ptr
計算。