智能指针
Smart Pointer
与智能指针对应的是裸指针
智能指针的出现主要是为了解决内存泄漏的问题
可以自动释放内存
头文件为<memory>
注意:
make_***
的语法在C++14之后才引入- auto_ptr在C++11之后被舍弃
- 智能指针和野指针不要混用指代同一个对象
声明和初始化
#include <memory>
void main(void)
{
//unique_ptr
std::unique_ptr<int> p1;
p1 = make_unique<int>(100);//100为构造函数的参数(初始化)
std::unique_ptr<int> p2 {new int(100)};
std::unique_ptr<int> p3 {make_unique<int>(100)};//如上,但是效率更高,在11之前的版本更安全
//也可以使用new shared_ptr<int>(new int(100), delfunc)这种残疾模式来初始化
//或者shared_ptr<int> p(new int(100), delfunc);
//shared_ptr
std::shared_ptr<int> p4;
p4 = make_shared<int>(100);
std::shared_ptr<int> p5 {new int(100)};
std::shared_ptr<int> p6 {make_shared<int>(100)};
}
关于的初始化应用<——其实这篇文章结构是一拖四,不过我暂时没有打算写这部分内容,所以将就用一下
unique_ptr
唯一指针
逻辑
不能复制,独占
删除器在编译时绑定,0额外开销
使用
unique_ptr<int> p2(p1.release())
unique_ptr<int> p2 = move(p1)
来转移控制权
shared_ptr
共享指针
逻辑
共享指针会记录指向同一个内存空间的共享指针个数
当最后一个共享指针被释放时,其指向的空间也会被释放
其实听起来蛮简单的,实现好像也蛮简单的,提示:自定义指针运算符,模板类,构造函数,析构函数
weak_ptr
逻辑
为了解决循环引用
不拥有资源,无法释放
若需访问资源要使用wp.lock()
取出一个shared_ptr来访问
使用
声明和初始化
weak_ptr<int> p = make_shared<int>(100)
需要任意shared_ptr进行赋值
使用
wp.lock()
返回裸指针的shared_ptr,如果计数为0,返回nullptrwp.use_count()
expired()
判断所观察资源是否已经释放
使用weak_ptr作为成员变量的类型即可解决循环引用
小东西
auto_ptr
待写
boost
待写
shared_from_this
待写
成员函数
- 通用
ptr.get()
会返回一个对应的裸指针ptr.reset()
会将ptr指向NULL,(并且原share计数减1)reset()
可以有参数,参数为指向的新空间
ptr.release()
解绑,返回裸指针(并且原share计数减1)ptr.swap(x)
与x互换
- shared_ptr
str.use_count()
返回引用计数str.unique()
检查是否独占
自定义删除行为
void close_file(FILE* fp){
if(fp == nullptr) return;
fclose(fp);
cout << "File closed." << endl;
}
int main(){
FILE* fp = fopen("data.txt","w");
//unique_ptr
unique_ptr<FILE,decltype(&close_file)> ufp {fp,close_file};//模板类型第二个要写删除器类型,在第二个参数写上删除器
//shared_ptr
shared_ptr<FILE> sfp {fp,close_file};//直接在第二个参数写上删除器
}
注意事项
-
不分配任何值时为nullptr
-
仅提供->,*,==运算符,没有+,-,++,--,[]等运算符
-
不要使用栈指针(因为智能指针使用delete释放空间,所以在构造时也需要new出来的空间)
-
空指针请用nullptr表示
- nullptr是C++11之后的关键字,而NULL是宏定义为0,在类型推导时可能会出错
-
unique_ptr
- 把unique_ptr赋值为nullptr会释放原指针空间
-
shared_ptr
- 不要使用同一个原始指针进行默认构造
shared_ptr<int> p2(num)
- 正确方法是
shared_ptr<int> p2(p1)
- 会有一点点额外性能开销
- 不要使用同一个原始指针进行默认构造
循环引用
两个类互相拥有一个对方的shared_ptr成员变量
分别建立两个类的shared_ptr对象,把成员变量设为彼此
就会造成死锁
无法释放