C++11 中的 Smart Pointer(shared_ptr/weak_ptr/unique_ptr) 总结
1. shared_ptr
- Shared Ownership
- source code
1.1 construct
shared_ptr<int> p = make_shared<int>(88);
shared_ptr<int> p1(new int(88));
auto p2 = make_shared<int>(88);
auto p3(p2);
1.2 why make_shared is prefered?
Consider calling a function that takes two smart pointers in input,like this:
void function(std::unique_ptr<A>(new A()), std::unique_ptr<B>(new B())) { ... }
Suppose that new A() succeeds, but new B() throws an exception: you catch it to resume the normal execution of your program. Unfortunately, the C++ standard does not require that object A gets destroyed and its memory deallocated: memory silently leaks and there’s no way to clean it up. By wrapping A and B into std::make_uniques you are sure the leak will not occur:
void function(std::make_unique<A>(), std::make_unique<B>()) { ... }
The point here is that std::make_unique & std::make_unique are now temporary objects, and cleanup of temporary objects is correctly specified in the C++ standard: their destructors will be triggered and the memory freed. So if you can, always prefer to allocate objects using std::make_unique & std::make_unique.
1.3 circle reference(循环引用)
struct Player
{
std::shared_ptr<Player> companion;
~Player() { std::cout << "~Player\n"; }
};
int main()
{
std::shared_ptr<Player> jasmine = std::make_shared<Player>();
std::shared_ptr<Player> albert = std::make_shared<Player>();
jasmine->companion = albert; // (1)
albert->companion = jasmine; // (2)
}
1.4 example to manage array
1.5 tips
- 不使用相同的内置指针值初始化,或reset多个智能指针
- 不delete get()返回的指针
- 不使用get()初始化或reset另一个智能指针
- get()返回的智能指针可能变成dangling pointer
- 如果智能指针管理的内存不是new出来的,需要提供删除器
2 weak_ptr
- std::weak_ptr — like a std::shared_ptr, but it doesn’t increment the counter.
2.1 construct
std::shared_ptr<int> p_shared = std::make_shared<int>(100);
std::weak_ptr<int> p_weak1(p_shared);
std::weak_ptr<int> p_weak2(p_weak1);
2.2 reference counter not increase
std::shared_ptr<int> p_shared = std::make_shared<int>(100);
std::weak_ptr<int> p_weak(p_shared);
// ...
std::shared_ptr<int> p_shared_orig = p_weak.lock();
//
2.3 check object expired or not
std::shared_ptr<int> p_shared = std::make_shared<int>(100);
std::weak_ptr<int> p_weak(p_shared);
//...
if(!p_weak.expired() && p_weak.lock()) //check ptr validate or not
{
//...
}
2.4 convert to shared_ptr
std::shared_ptr<int> p_shared_orig = p_weak.lock();
2.5 solve circle reference
3 unique_ptr
3.1 construct
std::unique_ptr<int> p = std::make_unique<int>(88);
std::unique_ptr<int> p1(new int);
3.2 unique_ptr cannot be copied
void test(std::unique_ptr<int>& a) //para should be a reference
{
std::cout << *a << std::endl;
}
int main(void)
{
std::unique_ptr<int> a = std::make_unique<int>(88);
std::unique_ptr<int> b = a; //error
test(a);
//test(std::move(a));
return 0;
}