C++ 进阶 ----智能指针

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;


}

结果 之进行了一次构造和析构 证明没有深拷贝

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 避免悬空指针。

7总结

在这里插入图片描述

发布了27 篇原创文章 · 获赞 4 · 访问量 1338

猜你喜欢

转载自blog.csdn.net/weixin_45639955/article/details/104295196