1基本概念
1.1指针的危害:
指针未初始化
野指针:
内存泄漏(申请动态内存 未释放)
1.2分类
1.3本质
将指针封装为类对象成员,并在析构函数里删除指针指向的内存。
1.4不同
名称 | 不同 |
---|---|
auto_ptr | 马上删除。 |
unique_ptr | 马上删除。 |
scoped_ptr | 马上删除。 |
shared_ptr | 计数为0删除。 |
weak_pt | 不删除 |
2auto_ptr
2.1作用
对作用域内的动态分配对象的自动释放
2.2基本类型
int *p=new int(10);
cout<<*p<<endl;//这样会导致内存泻露 通过valgrind ./a.out 就可以看出申请一个 释放0个 泄露4个字节
//智能指针
miniSTL::auto_ptr<int> ap(p);
cout<<*ap<<endl;//ap等同与p 通过valgrind ./a.out 就可以看出申请一个 释放1个 无泄露
2.3类类型
Test *t=new Test;
t->Func();//通过valgrind ./a.out 就可以看出申请一个 释放0个 泄露1个字节
miniSTL::auto_ptr<Test> apt(t);
t->Func();//通过valgrind ./a.out 就可以看出申请一个 释放1个 无泄露
2.4缺陷
2.4.1两个auto_ptr不能同时拥有同一个对象
int *p=new int(10);
cout<<*p<<endl;
auto_ptr<int> ap1(p);
const auto_ptr<int> ap2(p);//erro :double free 导致内存泄露
cout<<*ap1<<" ----"<<endl;
2.4.2auto_ptr不能管理数组指针
#include <memory>
using namespace std;
int main(){
int*pa=new int[10];
auto_ptr<int>ap(pa);
}
2.4.3auto_ptr被拷贝或被赋值后,失去对原指针的管理.这种情况被称为指针所有权传递。
赋值
auto_ptr<int> ap3=ap1;
cout<<*ap1<<endl;//段错误(吐核)
//错误原因 是因为ap1 把指针给了ap3 而自己为了避免2次释放 所以给自己赋值为空
cout<<*ap3<<endl;//正常
拷贝
void Func(auto_ptr<int> ap){
cout << *ap << endl;
}
int main(){
int*p = new int(10);
auto_ptr<int> ap(p);
cout<< *ap <<endl;
Func(ap);
//段错误
cout<< *ap <<endl;
}
2.4.4auto_ptr不能作为容器对象,因为STL容器中的元素经常要支持拷贝,赋值等操作。
在这里插入代码片
3unique_ptr(代替auto_ptr)
3.1特点
让指针不赋值,不拷贝 ,具体实现函数把其私有化
template<class T>
class unique_ptr{
T* m_p;
private:
unique_ptr(const unique_ptr& a);
unique_ptr& operator=(const unique_ptr& a);
};
4scoped_ptr
4.1作用
与unique_ptr相似,在本作用域中使用不能复制与赋值。
4. 2与unique_ptr区别
将拷贝构造函数 赋值运算符重载 函数禁用
class auto_ptr{
T * m_p;
public:
auto_ptr(T* p):m_p(p){}
auto_ptr(const auto_ptr& p):m_p(p.m_p)=delete
auto_ptr& operator=(const auto_ptr& a)=delete
}
5shared_ptr
5.1优势
//使用shared_ptr可以可以解决智能指针拷贝和赋值问题
//写时copy技术
shared_ptr<Test> sp(new Test(10));
shared_ptr<Test> sp2(sp);
cout<<*sp<<endl;
cout<<*sp2<<endl;
本质:sp 和sp2 共享了一个地址 但是不会出现2次释放
5.2测试
#include<iostream>
#include<memory>
using namespace std;
class Test{
int m_n;
public:
Test(int n):m_n(n){
cout<<"construct"<<m_n<<endl;
}
Test(){
cout<<"construct"<<m_n<<endl;
}
~Test(){
cout<<"destructor"<<m_n<<endl;
}
void Func()const{
cout<<"func"<<endl;
}
friend ostream& operator<<(ostream& os,const Test& t){
os<<"Test ("<<t.m_n<<")";
return os;
}
};
void Func(shared_ptr<Test> p){
cout<<p<<endl;
}
int main(){
shared_ptr<Test> sp(new Test(10));
shared_ptr<Test> sp2(sp);
cout<<*sp<<endl;
cout<<*sp2<<endl;
Func(sp);
cout<<(*sp)<<endl;
}
结果 之进行了一次构造和析构 证明没有深拷贝
扫描二维码关注公众号,回复:
9212553 查看本文章
construct 10
Test(10)
Test(10)
Test(10)
Test(10)
destructor
5.3问题:循环引用问题
#include<iostream>
#include<memory>
using namespace std;
class B;
class A{
public:
A(){cout<<"A construct"<<endl;}
~A(){cout<<"A destruct"<<endl;}
//第一次情况
//shared_ptr<B>m_b;
//第二次请况 改正情况
weak_ptr<B> m_b;
};
class B{
public:
B(){cout<<"B construct"<<endl;}
~B(){cout<<"B destruct"<<endl;}
shared_ptr<A> m_a;
};
int main(){
shared_ptr<A> pa(new A);
shared_ptr<B> pb(new B);
pa->m_b=pb;
pb->m_a=pa;//两个赋值之间只要去掉一次赋值 既AB就都可以析构
/*第一次结果
[root@foundation66 c++]# ./a.out
A construct
B construct
导致循环引用问题的原因是:如果A想要析构 那么首先的析构A的成员m_b 而mb如果要析构 那末又的先析构m_a所以出现了循环的请况
*/
//解决方式weak_ptr
/*[root@foundation66 c++]# g++ 8_4shared_ptr_problem.cpp -std=c++11
* [root@foundation66 c++]# ./a.out
* A construct
* B construct
* B destruct
* A destruct
*/
}
6weak_ptr
解决shared_ptr循环引用问题
6.1好处
1 打破递归的依赖关系
2 使用一个共享的资源但是不要所有权,不添加引用计数
3 避免悬空指针。