前言
c++最开始设计没有考虑gc(garbage collection)机制,后续c++11推出后STL标准库中增加了三个智能指针类,合理运用下可以让c++程序员摆脱忘记delete或者free的困扰
shared_ptr原理是引用计数,用于指针需要被传递复制的时候
weak_ptr主要就是为了配合shared_ptr防止出现循环引用(两个对象各持有各自的shared_ptr, 都无法先释放)
unique_ptr不可复制,离开作用域自动销毁,但是可以移动拷贝
一、语法使用
1.1 shared_ptr语法
// 测试类
class Test {
public:
void test() {
}
};
/* shared_ptr语法 */
// 1.初始化方式
std::shared_ptr<Test> sp(new Test()); // 正确,构造函数初始化
std::shared_ptr<Test> sp1 = std::make_shared<Test>(); // 正确,make_shared初始化
std::share_ptr<Test> sp2;
sp2.reset(new Test()); // 正确,reset初始化
std::shared_ptr<Test> sp3 = new Test(); // 错误, shared_ptr是一个类,构造的sp是一个对象,不可以直接用指针赋值
// 除非重载赋值运算符=特殊处理,但是shared_ptr没有重载=
// 2.其他操作
Test sp1 = *sp; // 重载*运算符 获取原始指针实际值
sp->test(); // 重载->运算符 调用保存的原始指针成员函数
Test *sp2 = sp.get(); // 获取原始指针
if (sp) {} // 重载bool()函数,判断指针是否为空
1.2 weak_ptr语法
/* weak_ptr语法 */
// 1.初始化方式
std::shared_ptr<Test> sp(new Test());
std::weak_ptr<Test> sp_weak(sp); // 通过shared_ptr构造
std::weak_ptr<Test> sp_weak1 = sp; // 通过shared_ptr赋值构造
std::weak_ptr<Test> sp_weak2(sp_weak); // 通过weak_ptr构造
// 2.其他操作
std::shared_ptr<Test> sp3 = sp_weak.lock(); // weak_ptr不能直接操作原始指针,需要的话需调用lock升级为shared_ptr
if (sp_weak.expired()) {} // 判断绑定的shared_ptr是否已析构
1.3 unique_ptr语法
/* unique_ptr语法 */
// 1.初始化方式
std::unique_ptr<Test> up(new Test()); // 构造函数初始化
std::unique_ptr<Test> up1 = std::make_unique<Test>(); // c11暂不支持,c17以后支持
std::unique_ptr<Test> up2;
up2.reset(new Test()); // reset初始化
//2.其他操作
// 2.其他操作
Test up1 = *up; // 重载*运算符 获取原始指针实际值
up->test(); // 重载->运算符 调用保存的原始指针成员函数
Test *up2 = up.get(); // 获取原始指针
if (up) {} // 重载bool()函数,判断指针是否为空
1.4 三指针的区别
shared_ptr 和 unique_ptr在语法上没有区别,唯一的区别的是shared_ptr支持赋值共享,unique_ptr不允许赋值(原理是禁用赋值构造)但是可以引用传递
weak_ptr是专门用来解决shared_ptr循环引用的问题的,本身不能操作原始指针
二、shared_ptr代码实现
1.1 shared_ptr实现
#include <iostream>
using namespace std;
template <class T>
class shared_ptr {
private:
// 保存真实指针
T* ptr_;
// 指向引用计数
int* ref_count_;
public:
shared_ptr(T *t) {
ptr_ = t;
// 初始化引用计数
if (ref_count_ == NULL) {
ref_count_ = new int(1);
}
}
shared_ptr(shared_ptr& ptr) {
ptr_ = ptr->ptr_;
// 引用计数加1
ref_count_ = ptr->ref_count_;
(*ref_count_)++;
}
void operator =(shared_ptr& ptr) {
ptr_ = ptr->ptr_;
// 引用计数加1
ref_count_ = ptr->ref_count_;
(*ref_count_)++;
}
T* get() {
return ptr_;
}
T operator *() {
return *ptr_;
}
T* operator ->() {
return ptr_;
}
};
class A {
public:
A() {}
int test() {
return 1;
}
};
int main () {
shared_ptr<A> sp(new A);
cout << sp->test() << endl;
return 0;
}
shared_ptr使用注意事项
- 尽量不要使用get()获取原始指针,防止其他删除原指针造成double free
- 如果类要返回this指针,最好使类继承enable_shared_from_this,然后 return shared_from_this();