1.概念

智能指针是为了解决C中指针在动态分配内存过程中的内存泄露、悬空指针、野指针等问题所提出的C++标准类模板库。C11标准中放在 中。

C++的智能指针包括:共享指针(std::shared_ptr),独占指针(std::unique_ptr),弱指针(std::weak_ptr)。

1.1 独占指针 unique_ptr

特点

独占所有权,同一时间只能有一个unique_ptr指向某个对象。不能复制,只能移动。

适用场景

当需要唯一控制一个对象时,例如管理动态数组或避免资源共享。

独占指针被禁止使用拷贝构造函数,仅能通过移动构造传递自身以保证指针所有权的唯一性。

使用方法

  1. 布尔转换

    智能指针可以直接通过布尔值判断指针是否存在,和C中的指针一致。 if (ptr) {//do sth};

  2. operator * 和operator ->

    智能指针使用 * 和 -> 来访问智能指针的成员 *(ptr).func(); ptr->func();

  3. make_unique和new构造

    C++中有两种使用智能指针的方式。
    一种是通过std::unique_ptr<T>ptr = std::make_unique<T>(arg)直接创建堆上内存和智能指针。 另一种是通过std::unique_ptr<T> ptr(new(T)(arg))先申请内存得到野指针再创建智能指针,该方法下同时创建多个智能指针时可能会发生内存泄露。

     process_object(std::unique_ptr<MyClass>(new MyClass(1)),  std::unique_ptr<MyClass>(new MyClass(2)));
     //后面的new抛出异常,此时第一个的智能指针会内存泄漏
    
  4. get()

    智能指针通过ptr.get()来获得原始指针。
    int * raw_ptr = ptr.get();

  5. reset()

    智能指针通过ptr.reset()来释放当前对象,ptr自动指向nullptr。
    ptr.get();

  6. swap()

    智能指针通过swap()来交换两个unique_ptr的指向的内容,他们依然是独占的。
    ptr1.swap(ptr2);

  7. release()

    独占指针通过ptr.release()来释放智能指针对一个内存的所有权,返回指向这个内存对象的裸指针。
    int * released_ptr = ptr.release();

  8. 仅具有移动语义

    独占指针通过移动语义的方式实现资源的独占传递,独占指针仅具有移动语义。
    std::unique_ptr ptr1 = std::move(ptr2);

1.2 共享指针 shared_ptr

特点

共享所有权,多个shared_ptr可以指向同一个对象,通过引用计数跟踪使用情况。当计数为零时,自动释放内存。

适用场景

当多个部分需要共享访问同一个对象时。

循环计数问题: 当存在共享指针互相指向时,离开作用域时两边的共享指针都会因为引用计数不为0而不被释放。本质是类似死锁的现象,通过将其中的一个替换为weak_ptr解决。

使用方法

  1. 布尔转换

    智能指针可以直接通过布尔值判断指针是否存在,和C中的指针一致。 if (ptr) {//do sth};

  2. operator * 和operator ->

    智能指针使用 * 和 -> 来访问智能指针的成员
    *(ptr).func();
    ptr->func();

  3. make_unique和new构造

    std::unique_ptr<T>ptr = std::make_unique<T>(arg)直接创建堆上内存和智能指针。
    std::unique_ptr<T> ptr(new(T)(arg))先申请内存得到野指针再创建智能指针,可能会发生内存泄露。

  4. get()

    智能指针通过ptr.get()来获得原始指针。
    int * raw_ptr = ptr.get();

  5. reset()

    智能指针通过ptr.reset()来释放当前对象,ptr自动指向nullptr。
    ptr.get();

  6. swap()

    智能指针通过swap()来交换两个shared_ptr的指向的内容,他们依然是独占的。
    ptr1.swap(ptr2);

  7. use_count()

    共享指针通过use_count()来获得指针的引用计数,从而实现在不存在使用内存的共享指针以后自动释放堆上内存。会导致循环计数,需要和weak_ptr配合使用。
    ptr.use_count()

  8. owner_before() 共享指针通过owner_before()来判断两个共享指针或者弱指针是否使用同一个控制块(指向同一个堆内存,共享引用计数),若为false,则相同。
    ptr.owner_before()

1.3 弱指针 weak_ptr

特点

弱引用,不增加引用计数。对指针内容是只读的,无对指针内容的修改能力,是一种对指针内容的观察者,与shared_ptr共用引用计数。用以解决shared_ptr的循环引用问题。weak_ptr不能直接从裸指针创建,没有make方法。

适用场景

避免循环引用导致的内存泄漏。

使用方法

  1. 布尔转换

    智能指针可以直接通过布尔值判断指针是否存在,和C中的指针一致。
    if (ptr) {//do sth};

  2. 依赖shared_ptr进行构造

    弱指针是对指针内容只读的引用,不能通过裸指针直接构造,也没有make方法。

  3. lock()

    不能通过*或者->操作符直接访问成员,没有get方法获得裸指针。 当需要访问的修改指针内容时,弱指针通过weak_ptr.lock()升级为shared_ptr。

     if (auto temp = weak.lock()){
         //do sth
     }
    
  4. reset()

    智能指针通过ptr.reset()来释放shared_ptr当前对象,ptr自动指向nullptr。
    ptr.get();

  5. swap()

    智能指针通过swap()来交换两个weak_ptr的指向的内容,他们依然是独占的。
    ptr1.swap(ptr2);

  6. use_count()

    弱指针通过use_count()来获得指针的引用计数,弱指针不会增加引用计数。和shared_ptry一起配合使用可以解决循环计数问题。
    ptr.use_count()

  7. owner_before()

    共享指针通过owner_before()来判断两个共享指针或者弱指针是否使用同一个控制块(指向同一个堆内存,共享引用计数),若为false,则相同。
    ptr.owner_before()