..
智能指针
智能指针依赖C++自行调用析构函数的特点,使用对象的生命周期来自动管理在堆空间申请的内存。
auto_ptr
auto_ptr在C++98中就存在,本身存在明显的问题。
所有权转义
当auto_ptr进行相互赋值操作之后,会进行所有权转移,老的指针会被设置为空指针,后续只能使用新的指针进行解引用等操作。
#include <memory>
using namespace std;
int main() {
auto_ptr<int> p1(new int);
auto_ptr<int> p2 = p1;
*p1 = 1; // 此时对象的操作权限已经转移到p2上,p1被置空。
return 0;
}
导致以下问题:
- 不能结合STL容器使用
不适用于管理数组
auto_ptr在析构时使用的方法为delete,而当析构数组时,需要使用delete[],所以不能用auto_ptr管理数组指针。
#include <memory>
using namespace std;
int main() {
int n = 100000;
while (n--) {
auto_ptr<int> p1(new int[10000]);
} // 产生内存泄漏
return 0;
}
unique_ptr
unique_ptr出现于C++11,不支持拷贝和赋值操作,只能通过右值引用的方式转移资源的所有权。默认情况下于auto_ptr一样使用delete来析构资源,但也可以通过自定义删除器来实现对资源的析构操作,支持lambda表达式实现自定义删除器,同时支持了对数组资源的管理。
删除拷贝构造和赋值操作
#include <mempry>
using namespace std;
int main() {
unique_ptr<int> p1(new int(32));
// unique_ptr<int> p2(p1); 拷贝构造函数产生编译报错
// unique_ptr<int> p2 = p1; 赋值操作产生编译报错
unique_ptr<int> p2(std::move(p1)); // 将p1转义为右值即可以调用移动构造函数
unique_ptr<int> p3 = std::move(p2); // 同样可以实现资源的所有权转移
return 0;
}
支持管理数组
#include <memory>
using namespace std;
int main() {
unique_ptr<int[]> p(new int[100]);
return 0;
}
自定义删除器
#include <memory>
#include <iostream>
using namespace std;
class A {};
class ADeleter1 {
public:
void operator()(A* p) {
cout << "deleted p 1" << endl;
}
};
void ADeleter2(A* p) {
cout << "deleted p 2" << endl;
}
int main() {
unique_ptr<A, ADeleter1> p(new A);
unique_ptr<A, decltype(ADeleter2)*> p(new A, ADeleter2);
return 0;
}
shared_ptr
shared_ptr出现于C++11,采用引用计数的方法,解决了auto_ptr和unique_ptr存在的问题,同时也支持指定删除器。但shared_ptr也存在自己的问题。
循环引用
#include <memory>
#include <iostream>
using namespace std;
class A {
public:
shared_ptr<B> b;
~A() {
cout << "delete A" << endl;
}
};
class B {
public:
shared_ptr<A> a;
~B() {
cout << "delete B" << endl;
}
}
int main() {
shared_ptr<A> pa(new A);
shared_ptr<B> pb(new B);
pa->b = pb;
pb->a = pa;
return 0;
}
当两个类互相持有对方的shared_ptr并相互指向时,引用计数会被置为2,当生命周期到达时,会使拥有的shared_ptr计数为1,所以并没有执行对应的析构函数,导致内存泄漏。
weak_ptr
weak_ptr出现于C++11,用来解决shared_ptr的循环引用问题,只能使用weak_ptr或者shared_ptr构造,weak_ptr的赋值操作不会使shared_ptr的引用计数变化。weak_ptr不能对指针进行解引用操作,类似只读的操作,但可以通过lock方法拷贝一个shared_ptr进行操作,当资源已经被析构时,调用lock方法会返回一个空的shared_ptr。