什么是智能指针?
- 智能指针就是用一个类来封装一个指针
- 主要负责自动的来释放内存,防止发生内存泄漏
智能指针的思想
智能指针中存储的是指向动态对象的指针,用于动态对象生存周期的控制,能够确保自动且正确的销毁动态对象,防止内存泄漏。智能指针的主要作用就是利用栈智能指针离开作用域的时候调用析构函数释放资源。
下面我们介绍四类智能指针
auto_ptr
auto_ptr是C++98引入的,但是现在已经基本上弃用了,虽然它可以像其他的智能指针一样自动释放内存,但是它的缺陷还是太明显了。auto_ptr对象p赋值给另一个对象q时,p就失去了对它的内存的访问权限,所以说不能用多个auto_ptr对象指向同一片内存,auto_ptr的访问权唯一。这就是auto_ptr最大的缺点。
下面我们用代码来看一下auto_ptr的缺点
#include<iostream>
#include<memory>
using namespace std;
int main()
{
int *p = new int(10);
auto_ptr<int> q1(p);
cout << q1.operator*() << endl;
//auto_ptr<int> q2(p); //error 多个智能指针不能指向同一片内存
auto_ptr<int> q2(q1);
cout << q2.operator*() << endl;
//cout << q1.operator*() << endl; //error 当q1用来初始化智能指针q2,那么q1就不能访问它原来指向的内存,访问权唯一
return 0;
}
后来在C++11中又引入了三个智能指针用来弥补auto_ptr的缺点:uniquep_ptr,wake_ptr,shared_ptr
unique_ptr
unique_ptr也被称为独占形智能指针,智能有一个指针对指向该对象,也无法通过拷贝构造产生新的智能指针对象,也无法用赋值操作产生新的智能指针对象。但是,他的对象所有权可以转移。
#include<iostream>
#include<memory>
using namespace std;
int main()
{
int *p = new int(10);
unique_ptr<int> q1(p);
cout << q1.operator*() << endl;
//unique_ptr<int> q2(p);
//cout << q2.operator*() << endl; 这里会崩溃,unique_ptr和auto_ptr一样,都不能用多个指针指向同一块对象
//unique_ptr<int> q2(q1); error unique_ptr不允许拷贝构造函数生成新对象
//unique_ptr<int> q2;
//q2 = q1; error unique_ptr不允许赋值运算生成新对象
return 0;
}
shared_ptr:共享式智能指针
为什么说shared_ptr是共享的智能指针?因为它可以用多个指针指向同一个对象,当最后一个指针被销毁时,该对象被释放。
原理:每个shared_ptr的拷贝的都是指向相同的内存,采用引用计数器的方法,允许多个智能指针指向同一个对象,没创建一个指针指向该对象时,智能指针内部的引用技术+1,每当少一个智能指针指向对象时,引用计数会-1,当计数为0的时候,智能指针会自动的释放动态分配的内存。
但是,shared_ptr有一个很大的缺陷,交叉引用
#include<iostream>
#include<memory>
using namespace std;
class B;
class A
{
public:
int count = 0;
shared_ptr<B> b;
A()
{
count++;
cout << "A::A()" << endl;
}
~A()
{
count--;
cout << "A::~A()" << endl;
}
};
class B
{
public:
int count1 = 0;
shared_ptr<A> a;
B()
{
count1++;
cout << "B::B()" << endl;
}
~B()
{
count1--;
cout << "B::~B()" << endl;
}
};
int main()
{
shared_ptr<A> p1(new A());
shared_ptr<B> p2(new B());
p1->a = p2;
p2->b = p1;
cout << p1->count << endl;
cout << p2->count1 << endl;
return 0;
}
这个程序运行的结果是A::A(),B::B(),两个类都没有调用析构函数,所以造成了内存泄漏。
当我们打印引用计数的时候发现都是1,这就说明编译器认为还有指针指向这两个内存,不能释放,这里就造成了内存泄漏。p1指向A类,B类中有一个指针a也指向A类,所以A类的引用计数为2,B类一样也是2,当主程序返回之后引用计数变为1,因为不为0,所以不能释放内存,所以造成泄漏。解决的方法就是弱智能指针。
weak_ptr
weak_ptr它指向一个shared_ptr管理的对象而不影响对象的生命周期,起辅助作用。它只引用,不计数。一块内存被shared_ptr和weak_ptr同时引用,当shared_ptr析构之后,不管有没有weak_ptr引用该内存,都会被释放。
所以在使用强弱智能指针的时候遵循一个原则就好,在初始化对像的时候用强智能指针shared_ptr,其余的地方全部用弱智能指针。