跳到主要内容

智能指针

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,返回nullptr
  • wp.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()检查是否独占

CSDN - C++ 智能指针

自定义删除行为

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对象,把成员变量设为彼此
就会造成死锁
无法释放