智能指针就是帮我们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;
}
运行结果:
文章图片
造成在这个的原因是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无法通过赋值的形式创建内存对象,即:
文章图片
这种方式也是错误的。
提前释放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;
}
运行结果:
文章图片
可以看出:
通过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;
}
运行结果:
文章图片
通过
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;
}
运行结果:
文章图片
四 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;
}
此时他们之前存在相互引用,但是已经方法已经返回了还没稀释
运行结果:
文章图片
解释原因可以参考:智能指针(三):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++ - Lambda表达式
- C++ - 子类与父类的同名成员变量
- C++|【C++】多态
- Qt|Qt之QTreeView的简单使用(含源码+注释)
- QT|QT---创建对话框3(形状可变对话框的实现)
- Qt学习之路|Qt项目-安防监控系统(解码编码转码)
- Qt探索之旅|Qt实现思维导图功能(二)
- QT|Qt状态机的使用
- C++|Qt-Q_OBJECT宏及控件提升导致的类重定义问题