簡介
可以獲取一個指針的所有權,且可以共享該所有權。
當最後一個屬主釋放掉指針的所有權時,該屬主將負責指針所指空間的釋放工作。
屬主釋放所有權的方式:
- 屬主被銷燬(析構);
- 屬主通過賦值操作改變了它的值;
- 屬主顯式調用 share_ptr::reset 函數。
共享所有權的方式:
- 通過拷貝另一個屬主;
注意:如果兩個 shared_ptr 通過同一個原始指針(非 shared_ptr) 構造,則它們將同時擁有該指針,而非共享該指針!當一個 shared_ptr 釋放掉原始指針指向的內存時,另一個 shared_ptr 將指向無效的空間!!且會發生 double free 錯誤。
#include <iostream>
#include <memory>
int main() {
int* p = new int(4);
std::shared_ptr<int> sp1 = std::shared_ptr<int>(p);
// 不行!!
std::shared_ptr<int> sp2 = std::shared_ptr<int>(p);
return 0;
}
一個 shared_ptr 和兩個指針關聯:
- owned pointer:多個 shared_ptr 間共享的那個指針。
- stored pointer:解引用指針時,將獲取這個指針指向的內容。
通常情況下,owned pointer = stored pointer 。兩者也可以不同(使用 aliasing 構造函數),如:owned pointer = &obj 且 stored pointer = &obj.member 。
構造
default (1) | constexpr shared_ptr() noexcept; |
---|---|
from null pointer (2) | constexpr shared_ptr(nullptr_t) : shared_ptr() {} |
from pointer (3) | template <class U> explicit shared_ptr (U* p); |
with deleter (4) | template <class U, class D> shared_ptr (U* p, D del); template <class D> shared_ptr (nullptr_t p, D del); |
with allocator (5) | template <class U, class D, class Alloc> shared_ptr (U* p, D del, Alloc alloc); template <class D, class Alloc> shared_ptr (nullptr_t p, D del, Alloc alloc); |
copy (6) | shared_ptr (const shared_ptr& x) noexcept; template <class U> shared_ptr (const shared_ptr<U>& x) noexcept; |
copy from weak (7) | template <class U> explicit shared_ptr (const weak_ptr<U>& x); |
move (8) | shared_ptr (shared_ptr&& x) noexcept; template <class U> shared_ptr (shared_ptr<U>&& x) noexcept; |
move from managed (9) | template <class U> shared_ptr (auto_ptr<U>&& x); template <class U, class D> shared_ptr (unique_ptr<U,D>&& x); |
aliasing (10) | template <class U> shared_ptr (const shared_ptr<U>& x, element_type* p) noexcept; |
形式(10)中,shared_ptr 的 owned pointer 爲 x 共享的指針,stored pointer 爲 p 。
#include <iostream>
#include <memory>
struct C { int* data; };
int main() {
std::shared_ptr<int> p1;
std::shared_ptr<int> p2(nullptr);
std::shared_ptr<int> p3(new int);
std::shared_ptr<int> p4(new int, std::default_delete<int>());
std::shared_ptr<int> p5(new int, [](int* p) {delete p; }, std::allocator<int>());
std::shared_ptr<int> p6(p5);
std::shared_ptr<int> p7(std::move(p6));
std::shared_ptr<int> p8(std::unique_ptr<int>(new int));
std::shared_ptr<C> obj(new C);
std::shared_ptr<int> p9(obj, obj->data);
std::cout << "use_count:\n";
std::cout << "p1: " << p1.use_count() << '\n';
std::cout << "p2: " << p2.use_count() << '\n';
std::cout << "p3: " << p3.use_count() << '\n';
std::cout << "p4: " << p4.use_count() << '\n';
std::cout << "p5: " << p5.use_count() << '\n';
std::cout << "p6: " << p6.use_count() << '\n';
std::cout << "p7: " << p7.use_count() << '\n';
std::cout << "p8: " << p8.use_count() << '\n';
std::cout << "p9: " << p9.use_count() << '\n';
return 0;
}
use_count:
p1: 0
p2: 0
p3: 1
p4: 1
p5: 2
p6: 0
p7: 2
p8: 1
p9: 2
使用 new 分配內存 | template <class T, class… Args> shared_ptr<T> make_shared (Args&&… args); |
---|---|
使用指定的 allocator 分配內存 | template <class T, class Alloc, class… Args> shared_ptr<T> allocate_shared (const Alloc& alloc, Args&&… args); |
使用 args 構造一個類型爲 T 的對象,並返回一個 shared_ptr,其中包含 owned pointer 和 stored pointer 指向構造的對象。
// make_shared
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> foo = std::make_shared<int> (10);
// same as:
std::shared_ptr<int> foo2 (new int(10));
auto bar = std::make_shared<int> (20);
auto baz = std::make_shared<std::pair<int,int>> (30,40);
std::cout << "*foo: " << *foo << '\n';
std::cout << "*bar: " << *bar << '\n';
std::cout << "*baz: " << baz->first << ' ' << baz->second << '\n';
return 0;
}
*foo: 10
*bar: 20
*baz: 30 40
// allocate_shared
#include <iostream>
#include <memory>
int main () {
std::allocator<int> alloc; // the default allocator for int
std::default_delete<int> del; // the default deleter for int
std::shared_ptr<int> foo = std::allocate_shared<int> (alloc,10);
auto bar = std::allocate_shared<int> (alloc,20);
auto baz = std::allocate_shared<std::pair<int,int>> (alloc,30,40);
std::cout << "*foo: " << *foo << '\n';
std::cout << "*bar: " << *bar << '\n';
std::cout << "*baz: " << baz->first << ' ' << baz->second << '\n';
return 0;
}
*foo: 10
*bar: 20
*baz: 30 40
賦值
copy (1) | shared_ptr& operator= (const shared_ptr& x) noexcept; template <class U> shared_ptr& operator= (const shared_ptr<U>& x) noexcept; |
---|---|
move (2) | shared_ptr& operator= (shared_ptr&& x) noexcept; template <class U> shared_ptr& operator= (shared_ptr<U>&& x) noexcept; |
move from (3) | template <class U> shared_ptr& operator= (auto_ptr<U>&& x); template <class U, class D> shared_ptr& operator= (unique_ptr<U,D>&& x); |
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> foo;
std::shared_ptr<int> bar (new int(10));
foo = bar; // copy
bar = std::make_shared<int> (20); // move
std::unique_ptr<int> unique (new int(30));
foo = std::move(unique); // move from unique_ptr
std::cout << "*foo: " << *foo << '\n';
std::cout << "*bar: " << *bar << '\n';
return 0;
}
重置
(1) | void reset() noexcept; |
---|---|
(2) | template <class U> void reset (U* p); |
(3) | template <class U, class D> void reset (U* p, D del); |
(4) | template <class U, class D, class Alloc> void reset (U* p, D del, Alloc alloc); |
形式(1)使 shared_ptr 變爲空(empty 不是 null)。其他形式則改變其共享的指針。
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> sp; // empty
sp.reset (new int); // takes ownership of pointer
*sp=10;
std::cout << *sp << '\n';
sp.reset (new int); // deletes managed object, acquires new pointer
*sp=20;
std::cout << *sp << '\n';
sp.reset(); // deletes managed object
return 0;
}
解引用
* 運算符 | element_type& operator*() const noexcept; |
---|---|
-> 運算符 | element_type* operator->() const noexcept; |
返回 stored pointer 所指向的內容。
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> foo (new int);
std::shared_ptr<int> bar (new int (100));
*foo = *bar * 2;
std::cout << "foo: " << *foo << '\n';
std::cout << "bar: " << *bar << '\n';
return 0;
}
foo: 200
bar: 100
#include <iostream>
#include <memory>
struct C { int a; int b; };
int main () {
std::shared_ptr<C> foo;
std::shared_ptr<C> bar (new C);
foo = bar;
foo->a = 10;
bar->b = 20;
if (foo) std::cout << "foo: " << foo->a << ' ' << foo->b << '\n';
if (bar) std::cout << "bar: " << bar->a << ' ' << bar->b << '\n';
return 0;
}
foo: 10 20
bar: 10 20
交換
成員函數 | void swap (shared_ptr& x) noexcept; |
---|---|
非成員函數 | template <class T> void swap (shared_ptr<T>& x, shared_ptr<T>& y) noexcept; |
交換兩者的所有權。
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> foo (new int(10));
std::shared_ptr<int> bar (new int(20));
foo.swap(bar);
std::cout << "*foo: " << *foo << '\n';
std::cout << "*bar: " << *bar << '\n';
return 0;
}
*foo: 20
*bar: 10
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> foo (new int(10));
std::shared_ptr<int> bar (new int(20));
swap(foo,bar);
std::cout << "foo: " << *foo << '\n';
std::cout << "bar: " << *bar << '\n';
return 0;
}
foo: 20
bar: 10
類型轉換
static_cast<T*>(sp.get()) 有效時纔可以 | template <class T, class U> shared_ptr<T> static_pointer_cast (const shared_ptr<U>& sp) noexcept; |
---|---|
dynamic_cast<T*>(sp.get()) 有效時纔可以 | template <class T, class U> shared_ptr<T> dynamic_pointer_cast (const shared_ptr<U>& sp) noexcept; |
const_cast<T*>(sp.get()) 有效時纔可以 | template <class T, class U> shared_ptr<T> const_pointer_cast (const shared_ptr<U>& sp) noexcept; |
返回的是 sp 的拷貝,意味着屬主數加一。
// static_pointer_cast
#include <iostream>
#include <memory>
struct A {
static const char* static_type;
const char* dynamic_type;
A() { dynamic_type = static_type; }
};
struct B: A {
static const char* static_type;
B() { dynamic_type = static_type; }
};
const char* A::static_type = "class A";
const char* B::static_type = "class B";
int main () {
std::shared_ptr<A> foo;
std::shared_ptr<B> bar;
foo = std::make_shared<A>();
// cast of potentially incomplete object, but ok as a static cast:
bar = std::static_pointer_cast<B>(foo);
std::cout << "foo's static type: " << foo->static_type << '\n';
std::cout << "foo's dynamic type: " << foo->dynamic_type << '\n';
std::cout << "bar's static type: " << bar->static_type << '\n';
std::cout << "bar's dynamic type: " << bar->dynamic_type << '\n';
return 0;
}
foo's static type: class A
foo's dynamic type: class A
bar's static type: class B
bar's dynamic type: class A
// dynamic_pointer_cast
#include <iostream>
#include <memory>
struct A {
static const char* static_type;
const char* dynamic_type;
A() { dynamic_type = static_type; }
};
struct B: A {
static const char* static_type;
B() { dynamic_type = static_type; }
};
const char* A::static_type = "class A";
const char* B::static_type = "class B";
int main () {
std::shared_ptr<A> foo;
std::shared_ptr<B> bar;
bar = std::make_shared<B>();
foo = std::dynamic_pointer_cast<A>(bar);
std::cout << "foo's static type: " << foo->static_type << '\n';
std::cout << "foo's dynamic type: " << foo->dynamic_type << '\n';
std::cout << "bar's static type: " << bar->static_type << '\n';
std::cout << "bar's dynamic type: " << bar->dynamic_type << '\n';
return 0;
}
Edit & Run
foo's static type: class A
foo's dynamic type: class B
bar's static type: class B
bar's dynamic type: class B
// const_pointer_cast
#include <iostream>
#include <memory>
int main() {
std::shared_ptr<const int> foo;
std::shared_ptr<int> bar;
foo = std::make_shared<const int>(10);
bar = std::const_pointer_cast<int>(foo);
std::cout << "*foo: " << *foo << '\n';
*bar = 20;
std::cout << "*foo: " << *foo << '\n';
return 0;
}
*foo: 10
*foo: 20
其他操作
獲取 stored pointer
element_type* get() const noexcept;
#include <iostream>
#include <memory>
int main () {
int* p = new int (10);
std::shared_ptr<int> a (p);
if (a.get()==p)
std::cout << "a and p point to the same location\n";
// three ways of accessing the same address:
std::cout << *a.get() << "\n";
std::cout << *a << "\n";
std::cout << *p << "\n";
return 0;
}
a and p point to the same location
10
10
10
獲取屬主數
long int use_count() const noexcept;
是否唯一
bool unique() const noexcept;
等價於 use_count() == 1 。
轉換爲布爾值
explicit operator bool() const noexcept;
stored pointer 爲 null -> false;不爲 null -> true 。
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> foo;
std::shared_ptr<int> bar (new int(34));
if (foo) std::cout << "foo points to " << *foo << '\n';
else std::cout << "foo is null\n";
if (bar) std::cout << "bar points to " << *bar << '\n';
else std::cout << "bar is null\n";
return 0;
}
foo is null
bar points to 34
關係運算符
支持 == , !=, < , <= , > , >= 。比較的是兩者的 stored pointer 。
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> a,b,c,d;
a = std::make_shared<int> (10);
b = std::make_shared<int> (10);
c = b;
std::cout << "comparisons:\n" << std::boolalpha;
std::cout << "a == b: " << (a==b) << '\n';
std::cout << "b == c: " << (b==c) << '\n';
std::cout << "c == d: " << (c==d) << '\n';
std::cout << "a != nullptr: " << (a!=nullptr) << '\n';
std::cout << "b != nullptr: " << (b!=nullptr) << '\n';
std::cout << "c != nullptr: " << (c!=nullptr) << '\n';
std::cout << "d != nullptr: " << (d!=nullptr) << '\n';
return 0;
}
comparisons:
a == b: false
b == c: true
c == d: false
a != nullptr: true
b != nullptr: true
c != nullptr: true
d != nullptr: false