1、智能指针的出现
在我们写程序的时候总会遇到一些需要new的问题,在没有智能指针的时候,我们只能收到的去delete,一旦我们忘记就会出现内存泄漏的问题。智能指针的出现就是为了解决这一问题,让我们new的对象,能够在使用完毕之后自己delete,而不用我们手动delete。
2、智能指针的历史
1、auto_ptr(C++98)
2、unique_ptr(C++11)
3、shared_ptr(C++11)
4、weak_ptr(C++11)
auto_ptr在C++98中提出在C++11中已经被抛弃,就不再叙述。
3、智能指针实现原理
智能指针是一种资源管理类,通过对原始指针进行封装,在资源管理对象进行析构时对指针指向的内存进行释放;通常使用引用计数方式进行管理。在指针进行拷贝的时候计数器会加1,而对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(减1,如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数(加1)。
实现简单的智能指针:
class Counter { friend class SmartPointer; public: Counter() { ptr = NULL; cnt = 0; } Counter(Object* p) { ptr = p; cnt = 1; } ~Counter() { delete ptr; } private: Object* ptr; int cnt; }; class SmartPointer { public: SmartPointer(Object* p) { ptr_counter = new Counter(p); } SmartPointer(const SmartPointer &sp) { ptr_counter = sp.ptr_counter; ++ptr_count->cnt; } SmartPointer& operator=(const SmartPointer &sp) { ++sp.ptr_counter->cnt; --ptr_counter->cnt; if (ptr_counter->cnt == 0) { delete ptr_counter; } ptr_counter = sp.ptr_counter; } ~SmartPointer() { - -ptr_counter->cnt; if (ptr_counter->cnt == 0) { delete ptr_counter; } } private: Counter* ptr_counter; };4.1 unique_ptr
当我们定义一个unique_ptr的时候,需要将其绑定到一个new返回的指针。
只能有一个uniqu_ptr指向对象,也就是说它不能被拷贝,也不支持赋值,但是我们可以通过move来移动。
unique_ptr<string> p3 (new string ("test"); unique_ptr<string> p4; p4 = p3;上述代码是错误的。但是如说使用auto_ptr就是没有问题的
auto_ptr<string> p1(new string ("test") ; auto_ptr<string> p2; p2 = p1;
unique_ptr<string> ps1, ps2; ps1 = new string("test"); ps2 = move(ps1); ps1 = new string("ok"); cout << *ps2 << *ps1 << endl;而且,程序试图将一个 unique_ptr 赋值给另一个时,如果源 unique_ptr 是个临时右值,编译器允许这么做;如果源 unique_ptr 将存在一段时间,编译器将禁止这么做
unique_ptr<string> test(const char * str) { unique_ptr<string> temp (new string (str)); return temp; } unique_ptr<string> ps; ps = demo('test");
4.2shared_ptr
采用引用计数的智能指针。 shared_ptr基于“引用计数”模型实现,多个shared_ptr可指向同一个动态对象,并维护了一个共享的引用计数器,记录了引用同一对象的shared_ptr实例的数量。当最后一个指向动态对象的shared_ptr销毁时,会自动销毁其所指对象(通过delete操作符)。shared_ptr的默认能力是管理动态内存,但支持自定义的Deleter以实现个性化的资源释放动作.
4.3weak_ptr
weak_ptr 提供对一个或多个 shared_ptr 实例所属对象的访问,但是,不参与引用计数。
5、循环引用
循环引用”简单来说就是:两个对象互相使用一个shared_ptr成员变量指向对方的会造成循环引用。
即A内部有指向B,B内部有指向A,这样对于A,B必定是在A析构后B才析构,对于B,A必定是在B析构后才析构A,这就是循环引用问题,违反常规,导致内存泄露。
解决循环引用方法:
1. 当只剩下最后一个引用的时候需要手动打破循环引用释放对象。
2. 当A的生存期超过B的生存期的时候,B改为使用一个普通指针指向A。
3. 使用weak_ptr打破这种循环引用,因为weak_ptr不会修改计数器的大小,所以就不会产生两个对象互相使用一个shared_ptr成员变量指向对方的问题,从而不会引起引用循环。