cpp_smart_pointer - ShenYj/ShenYj.github.io GitHub Wiki

智能指针

简介

传统指针存在的问题

  • 需要手动管理内存
  • 容易发生内存泄露(忘记释放、出现异常等)
  • 释放之后产生野指针

智能指针就是为了解决传统指针存在的问题

  • auto_ptr:属于C++98标准,在C++11中已经不推荐使用(有缺陷,比如不能用于数组)
  • shared_ptr:属于C++11标准
  • unique_ptr:属于C++11标准

auto_ptr

class Person {
public:
    int m_age;

    Person(int age) :m_age(age) {
        cout << "Person()" << endl;
    }
    ~Person() {
        cout << "~Person()" << endl;
    }

    void run() { }
};

int main() {
    /// 常规写法
    Person *p1 = new Person(10);
    /// 保证指针p使用完后释放
    delete p1;

    /// 利用`auto_ptr`智能指针, 注意没有 *
    /// 智能指针p 指向了堆空间的 Person 对象
    /// 不用像传统指针一样去管 delete
    /// 智能指针所指向的对象生命周期跟随智能指针,也就是智能指针被销毁了,对象也就随之释放内存
    auto_ptr<Person> p(new Person(20));

    p->run();
}

使用智能指针不要指向栈空间对象, 而是要指向堆空间对象

/// 这种写法会出现多次析构
Person person(20); /// 栈空间
auto_ptr<Person> p(&person);

智能指针的简单自实现

template <class T>
class SmartPointer {
    T *m_pointer;
public:
    SmartPointer(T *pointer) :m_pointer(pointer) { }
    ~SmartPointer() {
        if (m_pointer == nullptr) return;
        delete m_pointer;
    }

    T *operator->() {
        return m_pointer;
    }
};
SmartPointer<Person> p(new Person(20));
p->run();

shared_ptr

  • 多个shared_ptr可以指向同一个对象,当最后一个shared_ptr在作用域范围内结束时,对象才会被自动释放

    /// p1 p2 p3 p4 四个智能指针都指向了堆区那个 Person 对象
    shared_ptr<Person> p1(new Person(10));
    shared_ptr<Person> p2 = p1;
    shared_ptr<Person> p3 = p1;
    shared_ptr<Person> p4(p3);
  • 可以通过一个已存在的智能指针初始化一个新的智能指针

    shared_ptr<Person> p1(new Person());
    shared_ptr<Person> p2(p1);
  • 针对数组的用法

    shared_ptr<Person[]> persons(new Person[5]{});
    
    /// 不推荐,既然使用了智能指针,就没必要再考虑delete了
    shared_ptr<Person> ptr1(new Person[5]{}, [](Person *p) { delete[] p; });

shared_ptr的原理

  • 一个shared_ptr会对一个对象产生强引用(strong reference)
  • 每个对象都有个与之对应的强引用计数,记录着当前对象被多少个shared_ptr强引用着
    • 可以通过shared_ptr的use_count函数获得强引用计数
  • 当有一个新的shared_ptr指向对象时,对象的强引用计数就会+1
  • 当有一个shared_ptr销毁时(比如作用域结束),对象的强引用计数就会-1
  • 当一个对象的强引用计数为0时(没有任何shared_ptr指向对象时),对象就会自动销毁(析构)
/// 打印有多少个 shared_ptr 智能指针强引用着对象
/// 将p1 换成 p2 p3 p4 打印结果一样,因为指向的是同一个对象
shared_ptr<Person> p1(new Person(10));
cout << p1.user_count() << endl;  // 1
shared_ptr<Person> p2 = p1; 
cout << p1.user_count() << endl;  // 2
shared_ptr<Person> p3 = p1;
cout << p1.user_count() << endl;  // 3
shared_ptr<Person> p4(p3);
cout << p1.user_count() << endl;  // 4
Person *p = new Person(); // Person()

{
    shared_ptr<Person> p1(p);
}  // ~Person()

{
    shared_ptr<Person> p2(p);
} // ~Person()

上面这段代码的问题是: 一次构造,因为作用域的原因产生了两次析构

shared_ptr的循环引用

.

循环引用主要是针对智能指针,如果使用传统指针,都是手动管理内存

weak_ptr

使用 weak_ptr 解决循环引用

  • weak_ptr 会对一个对象产生弱引用

  • weak_ptr 可以指向对象解决 shared_ptr 的循环引用问题

    class Car {
    public:
        weak_ptr<Person> m_person;
    };
    
    class Person {
    public:
        shared_ptr<Car> m_car = nullptr;
    };
    
    int main() {
    
        shared_ptr<Person> person(new Person());
        shared_ptr<Car> car(new Car());
    
        person->m_car = car;
        car->m_person = person;
    
        return 0;
    }

unique_ptr

  • unique_ptr 也会对一个对象产生强引用,它可以确保同一时间只有1个指针指向对象
  • unique_ptr 销毁时(作用域结束时),其指向的对象也就自动销毁了
  • 可以使用 std::move 函数转移 unique_ptr 的所有权
/// ptr1强引用着person对象
unique_ptr<Person> ptr1(new Person());

/// 转移之后, ptr2 强引用着person对象
unique_ptr<Person> ptr2 = std::move(ptr1);
⚠️ **GitHub.com Fallback** ⚠️