std::unique_ptr
std::unique_ptr是一个独占所有权的指针,同一时间只能有一个std::unique_ptr 指向给定对象,当std::unique_ptr被销毁时,它指向的对象也会被释放;
动手试一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include<iostream> #include<memory> struct A { std::unique_ptr<int> u_ptr; A() { std::cout << "construct A" << std::endl; } ~A() { std::cout << "destruct A" << std::endl; } };
int main() { std::unique_ptr<A> u_ptr(new A()); return 0; }
|
std::shared_ptr
std::shared_ptr是一个共享所有权的智能指针,同一时间可以有多个 shared-ptr 指向给定对象,内部引用计数来统计引用数量,只有在最后一个 shared_ptr 被销毁时,指向的对象才会被释放;
std::shared_ptr的循环引用
如果两个 shared_ptr 相互引用,就会形成循环引用,导致两个 shared_ptr 对象不被释放,造成内存泄漏;
动手试一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #include<iostream> #include<memory>
struct B;
struct A { std::shared_ptr<B> s_ptr; A() { std::cout << "construct A" << std::endl; } ~A() { std::cout << "destruct A" << std::endl; } };
struct B { std::shared_ptr<A> s_ptr; B() { std::cout << "construct B" << std::endl; } ~B() { std::cout << "destruct B" << std::endl; } };
int main() { std::shared_ptr<A> a = std::make_shared<A>(); std::shared_ptr<B> b = std::make_shared<B>();
a->s_ptr = b; b->s_ptr = a;
std::cout << "main end" << std::endl; return 0; }
|
输出:
1 2 3 4 5
| Program returned: 0 construct A construct B main end # 程序结束了,但是a, b 没有调用析构函数,因为循环引用,a 和 b 的引用计数不会降为 0,他们的析构函数不会被调用,a,b没有被删除
|
循环引用需要使用 weak_ptr 来解决,weak_ptr 是不控制对象的生命周期的智能指针,它指向一个 shared_ptr管理的对象。当对象的所有 shared_ptr都消失后,即使还有 weak_ptr 指向该对象,该对象也会被正常销毁。
实现一个简单的 shared_ptr
shared_ptr 主要有两个成员变量:数据指针和计数指针;
需要实现他的构造函数、析构函数、拷贝构造、赋值运算符=重载、解引用运算符*重载、成员访问运算符->重载、以及获取引用计数函数。
动手试一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| #include <iostream>
template <typename T> class SharedPtr { public: explicit SharedPtr(T* p = nullptr) :ptr(p), ref_count(new size_t(1)) {}
SharedPtr(const SharedPtr& p) :ptr(p.ptr), ref_count(p.ref_count) { (*ref_count)++; }
~SharedPtr() { if (--(*ref_count) == 0) { delete ptr; delete ref_count; } }
SharedPtr& operator=(const SharedPtr& p) { if (this != &p) { if (--(*ref_count) == 0) { delete ptr; delete ref_count; } ptr = p.ptr; ref_count = p.ref_count; ++(*ref_count); } return *this; }
T& operator*() { return *ptr; }
T* operator->() { return ptr; }
size_t use_count() { return (*ref_count); }
private: T* ptr; size_t* ref_count; };
int main() { SharedPtr<int> p1(new int(5)); std::cout << p1.use_count() << std::endl;
SharedPtr<int> p2 = p1; std::cout << "p1 use count: " << p1.use_count() << std::endl; std::cout << "p2 use count: " << p2.use_count() << std::endl;
SharedPtr<int> p3; p3 = p1; std::cout << "p1 use count: " << p1.use_count() << std::endl; std::cout << "p2 use count: " << p2.use_count() << std::endl; std::cout << "p3 use count: " << p3.use_count() << std::endl; }
|