开启掘金成长之旅!这是我参与「掘金日新方案 12 月更文应战」的第3天,点击查看活动详情

在C++中,动态内存的办理是用一对运算符完成的:new和delete,new:在动态内存中为目标分配一块空间并回来一个指向该目标的指针,delete:指向一个动态独享的指针,毁掉目标,并开释与之相关的内存。

动态内存办理经常会出现两种问题:一种是忘记开释内存,会形成内存泄漏;一种是尚有指针引证内存的情况下就开释了它,就会产生引证非法内存的指针。

为了愈加简略(愈加安全)的运用动态内存,引进了智能指针的概念。智能指针的行为类似惯例指针,重要的差异是它负责主动开释所指向的目标。规范库提供的两种智能指针的差异在于办理底层指针的方法不同,shared_ptr答应多个指针指向同一个目标,unique_ptr则 独占 所指向的目标。规范库还界说了一种名为weak_ptr的伴随类,它是一种弱引证,指向 shared_ptr 所办理的目标,这三种智能指针都界说在memory头文件中。

1.auto_ptr

auto_ptr的赋值和仿制结构存在于一个办理权转移的操作,也就是说将赋值和仿制结构结束后,就只会有一个指针具有办理权,别的的一个指针就会指向NULL,这样就很简略形成NULL指针的解引证,然后导致内存溃散。

下面给一个比如去阐明auto_ptr的缺点:

class Dog {
public:
	Dog(int _age = 0) {
		age = _age;
		cout << "Dog: " << age << endl;
	}
	~Dog() {
		cout << "~Dog: " << age << endl;
	}
	void sound() {
		cout << "wang wang " << endl;
	}
	int age;
};
int main()
{
	auto_ptr<Dog>dog1(new Dog());
	dog1->sound();
	auto_ptr<Dog>dog2;
	dog2 = dog1;//仿制旧的dog1给dog2
	dog2->sound();//输出信息,仿制成功
	dog1->sound();//溃散
	return 0;
}

C++11的智能指针

经过检查,元凶巨恶是“dog2 = dog1;,这行代码,dog2彻底夺取了dog1的内存办理所有权,导致my_memory悬空,最后运用时导致溃散。所以,咱们需求找到新的方法去处理这个问题。就有了unique_ptr

2.unique_ptr

unique_ptr 由 C++11 引进,旨在替代不安全的 auto_ptr。它持有对目标的独有权——两个unique_ptr 不能指向一个目标,即 unique_ptr 不同享它所办理的目标。它无法仿制到其他 unique_ptr,无法经过值传递到函数,也无法用于需求副本的任何规范模板库 (STL)算法。

它将仿制结构函数和赋值运算符重载函数设置为了私有 并且只声明不完成,这种做法简略而粗犷,可是却很好的防止了别人在类外进行仿制和赋值,提高了代码的安全性。

C++11的智能指针

3.shared_ptr

shared_ptr 是一个规范的同享所有权的智能指针,答应多个指针指向同一个目标。shared_ptr 利用引证计数的方法完成了对所办理的目标的所有权的分享,即答应多个 shared_ptr 一起办理同一个目标。

shared_ptr 是为了处理 auto_ptr 在目标所有权上的局限性(auto_ptr 是独占的),在运用引证计数的机制上提供了能够同享所有权的智能指针,当然这需求额定的开支:

(1)shared_ptr 目标除了包含一个所具有目标的指针外,还必须包含一个引证计数代理目标的指针;

(2)时间上的开支主要在初始化和仿制操作上, * 和 -> 操作符重载的开支跟 auto_ptr 是相同;

(3)开支并不是咱们不运用 shared_ptr 的理由,,永远不要进行不成熟的优化,直到性能分析器告知你这一点。

class Dog {
public:
	Dog(int _age = 0) {
		age = _age;
		cout << "Dog: " << age << endl;
	}
	~Dog() {
		cout << "~Dog: " << age << endl;
	}
	void sound() {
		cout << "wang wang " << endl;
	}
	int age;
	shared_ptr<Dog>dog1;
	shared_ptr<Dog>dog2;
};
int main()
{
	shared_ptr<Dog>a(new Dog());
	shared_ptr<Dog>b(new Dog());
	cout << a.use_count() << endl;
	cout << b.use_count() << endl;
	a->dog1 = b;
	b->dog2 = a;
	cout << a.use_count() << endl;
	cout << b.use_count() << endl;
	return 0;
}

C++11的智能指针
C++11的智能指针

从显现的结果来看,结构的a和b在程序结束时都没有被析构,然后形成了内存泄漏。

4.weak_ptr

weak_ptr是对share_ptr的补充。是为了防止share_ptr的循环引证问题。

share_ptr 成功在它的使用计数,可是它的缺点也在于引证计数,例如在双向链表里,当只要两个节点时,cur的prev指针指向NULL,next节点的next指针执行NULL,如果完成为share_ptr的话就会出现循环引证的问题。