C++|C++ - 智能指针

智能指针就是帮我们C++程序员管理动态分配的内存的,它会帮助我们自动释放new出来的内存,从而避免内存泄漏!
内存泄漏的例子:
C++中内存泄漏的几种情况_Denny_Zoom的博客-CSDN博客_内存泄漏的几种情况
C++造成内存泄漏的原因汇总:_盖伊福克斯的博客-CSDN博客_c++内存泄漏
c++内存泄露(一):理解内存泄漏及内存泄漏常见情况_invisible_sky的博客-CSDN博客_c++ 内存泄露
一 auto_ptr
auto_ptr以前是用在C98中,C++11被抛弃,头文件一般用来作为独占指针
auto_ptr被赋值或者拷贝后,失去对原指针的管理
auto_ptr不能管理数组指针,因为auto_ptr的内部实现中,析构函数中删除对象使用delete而不是delete[],释放内存的时候仅释放了数组的第一个元素的空间,会造成内存泄漏。
auto_ptr不能作为容器对象,因为STL容器中的元素经常要支持拷贝,赋值等操作。
代码示例:

// Weak_Ptr_Use.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include #include using namespace std; class A { public: A(){ cout << "A Init" << endl; } ~A() { cout << "A Destory" << endl; } void show() { cout << "demo" << endl; } }; void test_auto_demo() { unique_ptr mma(new A()); cout << mma << endl; auto_ptr A_PTR(new A()); auto_ptrmm = A_PTR; //实质和std::move()语义一样。 cout << mm.get() << endl; cout << A_PTR.get() << endl; A_PTR->show(); }int main() { test_auto_demo(); system("pause"); return 0; }

运行结果:
C++|C++ - 智能指针
文章图片

造成在这个的原因是auto_ptrmm = A_PTR; //实质和std::move()语义一样。
这边A_PTR已经把所有权转给mm,此时A_PTR为空指针,空指针必然报错。。
所以unique_ptr比auto_ptr更加安全,实质上个人觉得应该是编译器对unique_ptr的处理更加灵活。

二 unique_ptr
C++11中用来替代auto_ptr
拷贝构造和赋值运算符被禁用,不能进行拷贝构造和赋值运算
虽然禁用了拷贝构造和赋值运算符,但unique_ptr可以作为返回值,用于从某个函数中返回动态申请内存的所有权,本质上是移动拷贝,就是使用std:move()函数,将所有权转移。
代码示例:
class A{ public: A(){ cout << "demo"<< endl; } void B(){ cout << "测试" << endl; } }; void unique_ptr_use() { unique_ptr A_ptr(new A()); A_ptr->B(); cout << A_ptr << endl; unique_ptr demo = A_ptr; //此时编译错误,无法通过赋值的方式传递指针地址,即与demo共享同一块内存 }

由上面代码可以看出,编译unique_ptr demo = A_ptr会报错,因为unique_ptr是只能单独享有对对象的独有权。
另外,unique_ptr无法通过赋值的形式创建内存对象,即:
C++|C++ - 智能指针
文章图片

这种方式也是错误的。

提前释放unique_ptr对象可以通过reset方法进行重置
代码示例:
void unique_ptr_use() { unique_ptr A_ptr(new A()); A_ptr->B(); cout << A_ptr << endl; A_ptr.reset(); cout << A_ptr << endl; }

运行结果:
C++|C++ - 智能指针
文章图片

可以看出:
通过reset方法 可以直接删除原始指针,并且重置为空。

我们可以通过转移所有权的方式,来使另一个指针拥有原先unique_ptr的地址。
代码示例:
void unique_ptr_use() { unique_ptr A_ptr(new A()); A_ptr->B(); cout << A_ptr << endl; unique_ptrBB = std::move(A_ptr); cout << A_ptr << endl; cout << BB << endl; }

运行结果:
C++|C++ - 智能指针
文章图片

通过std::move()方法,将A_ptr的对象转移到BB上面,A_ptr指针为空,BB拥有A_ptr指向的地址。

三 shared_ptr
多个指针可以指向相同的对象,调用release()计数-1,计数0时资源释放
use_count()查计数
reset()放弃内部所有权
share_ptr多次引用同一数据会导致内存多次释放
循环引用会导致死锁,
引用计数不是原子操作
shared_ptr可以实现多个对象共同托管一个指针,这个是unique_ptr做不到的。当曾经的托管对象接触对其托管时,系统会自动执行delete p释放内存,这样保证了内存不会泄漏。
代码示例:
void shared_ptr_use() { shared_ptr mm = make_shared(); mm->B(); cout <<"mm value:" << mm << endl; shared_ptr ff(mm); cout << "ff value:" << ff << endl; cout << "个数为" << ff.use_count() << endl; mm.reset(); //重置 cout <<"now ff:"<< ff << endl; cout << "个数为" << ff.use_count() << endl; cout <<"now mm:"<< mm << endl; }

运行结果:
C++|C++ - 智能指针
文章图片


四 weak_ptr
1.解决两个share_ptr互相引用产生死锁,计数永远降不到0,没办法进行资源释放,造成内存泄漏的问题。
2.使用时配合share_ptr使用,把其中一个share_ptr更换为weak_ptr
代码示例:
class B; class A{ public: A(){ cout << "A init!" << endl; } ~A(){ cout << "A Destroy" << endl; } void set_quote_ptr(shared_ptrmm) { m_b = mm; } private: shared_ptr m_b; }; class B{ public: B(){ cout << "A init!" << endl; } ~B(){ cout << "A Destroy" << endl; } void set_quote_ptr(shared_ptrmm) { m_a = mm; } private: shared_ptr m_a; }; void test_ptr() { shared_ptra_ptr = make_shared(); shared_ptrb_ptr = make_shared(); a_ptr->set_quote_ptr(b_ptr); b_ptr->set_quote_ptr(a_ptr); cout << "a count" << a_ptr.use_count() << endl; cout << "b count" << b_ptr.use_count() << endl; }int main() { test_ptr(); system("pause"); return 0; }

此时他们之前存在相互引用,但是已经方法已经返回了还没稀释
运行结果:
C++|C++ - 智能指针
文章图片

解释原因可以参考:智能指针(三):weak_ptr浅析_AlbertS的博客-CSDN博客_weakptr
解释了无法析构的原因,这里简单介绍一下。主要是相互引用时,导致引用记数无法为0;所以无法调用函数进行析构。
接下来解决的方案,是使用weak_ptr来替代其中一个shared_ptr,因为这样赋值的话,不会引发计数变化,修改完的代码如下:
#include "stdafx.h" #include #include using namespace std; class B; class A{ public: A(){ cout << "A init!" << endl; } ~A(){ cout << "A Destroy" << endl; } void set_quote_ptr(shared_ptrmm) { m_b = mm; } private: weak_ptr m_b; }; class B{ public: B(){ cout << "A init!" << endl; } ~B(){ cout << "A Destroy" << endl; } void set_quote_ptr(shared_ptrmm) { m_a = mm; } private: weak_ptr m_a; }; void test_ptr() { shared_ptra_ptr = make_shared(); shared_ptrb_ptr = make_shared(); a_ptr->set_quote_ptr(b_ptr); b_ptr->set_quote_ptr(a_ptr); cout << "a count" << a_ptr.use_count() << endl; cout << "b count" << b_ptr.use_count() << endl; }int main() { test_ptr(); system("pause"); return 0; }

运行结果:
C++|C++ - 智能指针
文章图片

可以明显的看出,已经被析构了。
【C++|C++ - 智能指针】

    推荐阅读