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;
}

运行结果:

在这里插入图片描述

造成在这个的原因是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++,开发语言)