开启掘金成长之旅!这是我参与「掘金日新方案 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;
}
经过检查,元凶巨恶是“dog2 = dog1;,这行代码,dog2彻底夺取了dog1的内存办理所有权,导致my_memory悬空,最后运用时导致溃散。所以,咱们需求找到新的方法去处理这个问题。就有了unique_ptr
2.unique_ptr
unique_ptr 由 C++11 引进,旨在替代不安全的 auto_ptr。它持有对目标的独有权——两个unique_ptr 不能指向一个目标,即 unique_ptr 不同享它所办理的目标。它无法仿制到其他 unique_ptr,无法经过值传递到函数,也无法用于需求副本的任何规范模板库 (STL)算法。
它将仿制结构函数和赋值运算符重载函数设置为了私有 并且只声明不完成,这种做法简略而粗犷,可是却很好的防止了别人在类外进行仿制和赋值,提高了代码的安全性。
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;
}
从显现的结果来看,结构的a和b在程序结束时都没有被析构,然后形成了内存泄漏。
4.weak_ptr
weak_ptr是对share_ptr的补充。是为了防止share_ptr的循环引证问题。
share_ptr 成功在它的使用计数,可是它的缺点也在于引证计数,例如在双向链表里,当只要两个节点时,cur的prev指针指向NULL,next节点的next指针执行NULL,如果完成为share_ptr的话就会出现循环引证的问题。