C++学习 四、智能指针总结

C++学习 四、智能指针总结

前言

之前分别学习了C++的三种智能指针shared_ptr,unique_ptr,weak_ptr的使用,本篇来做一个总结。

智能指针的作用

C/C++的一大特色就是指针,常用的堆指针分配方式需要手动进行内存空间的释放。

智能指针的出现为堆内存的管理提供了方便,降低了内存泄漏的风险。

智能指针的特点

智能指针实际上是通过类把堆指针进行封装,并通过重载运算符使得智能指针对象具有了类似普通指针的使用方式。

也就是说智能指针的使用类似普通指针,而实质上是一个对象。

智能指针最大的作用就是在合适的时间自动释放内存空间,防止出现内存泄漏的问题。

智能指针的生命周期与其作用域相关,超过作用域后将被销毁。

shared_ptr

共享指针

shared_ptr智能指针可以共享同一个普通指针,并具有引用计数块。

注意:shared_ptr的指针共享只能通过对象赋值操作、拷贝构造初始化实现。如果将一个普通指针分别给两个shared_ptr对象初始化,则会出现double free的问题。

因此,使用shared_ptr时,尽量不要与普通堆指针混用。

循环引用

循环引用时shared_ptr的常见问题。可以通过weak_ptr进行调试。

unique_ptr

unique_ptr智能指针独享内部指针的所有权,因此没有拷贝构造函数。

unique_ptr相比shared_ptr更适合指向数组,因为它重载了[]运算符:

std::unique_ptr<int []> vec(new int[8]);
vec[3] = 888;

weak_ptr

weak_ptr是shared_ptr的辅助指针,不具有普通指针的操作符。不能通过普通堆指针或nullptr构造。可以通过shared_ptr或者weak_ptr构造,但不会增加shared_ptr的引用计数。

weak_ptr常用于解决shared_ptr的循环引用问题。

手写一个shared_ptr类

要理解智能指针,我自己手写了一个类似shared_ptr的类实现:

#include <iostream>
#include <memory>
#include <assert.h>

class A;
class B;

template<typename T>
class mySmartPointer
{
private:
    T* ptr_;
    size_t* counter_;

public:
    explicit mySmartPointer(T* ptr=nullptr) {
        ptr_ = ptr;
        if (ptr != nullptr) 
            counter_ = new size_t(1);
        else
            counter_ = new size_t(0);
    };

    mySmartPointer(const mySmartPointer<T> &p) {
        ptr_ = p.ptr_;
        counter_ = p.counter_;
        if (p.ptr_ != nullptr)
            (*counter_)++;
    }

    ~mySmartPointer() {
        (*this->counter_)--;
        if ((*this->counter_) == 0)
        {
            delete this->ptr_;
            delete this->counter_;
        }
    };

    mySmartPointer<T>& operator=(const mySmartPointer<T> &p) {
        if (ptr_ == p.ptr_)
        {
            return *this;
        }

        if (ptr_ != nullptr)
        {
            (*counter_)--;
            if (*counter_ == 0)
            {
                delete ptr_;
                delete counter_;
            }
        }
       
        ptr_ = p.ptr_;
        counter_ = p.counter_;
        (*counter_)++;
        return *this;
    }

    T& operator*() {
        assert(this->ptr_ == nullptr);

        return *(this->ptr_);
    }

    T* operator->() {
        assert(this->ptr_ == nullptr);

        return this->ptr_;
    }

    T* get() {
        return ptr_;
    }

    int use_count() {
        return *counter_;
    }

    bool unique() {
        return bool(*counter_ == 1);
    }

    void reset(T* p=nullptr) {
        if (ptr_ != nullptr)
        {
            (*counter_)--;
            if (*counter_ == 0)
            {
                delete ptr_;
                delete counter_;
            }
        }
        ptr_ = p;
        if (p != nullptr)
            counter_ = new size_t(1);
        else
            counter_ = new size_t(0.);

    }
};

class A
{
public:
    std::shared_ptr<B> b_;
public:
    A(){
        std::cout << "construct A" << std::endl;
    }
    ~A(){
        std::cout << "destroy A" << std::endl;
    }
};

class B
{
public:
    std::shared_ptr<A> a_;
public:
    B(){
        std::cout << "construct B" << std::endl;
    }
    ~B(){
        std::cout << "destroy B" << std::endl;
    }
};


int main(int argc, char **argv) {
    // *** construct shared ptr *** ///
    mySmartPointer<double> m1(new double(0.6));
    std::cout << *m1 << std::endl;
    mySmartPointer<double> m2(m1);
    std::cout << *m2 << std::endl;
    std::cout << m1.use_count() << std::endl;
    std::cout << *(m1.get()) << std::endl;
    m1.reset();
    std::cout << m2.use_count() << std::endl;
    mySmartPointer<double> m3 = m2;
    std::cout << m2.use_count() << std::endl;
    //mySmartPointer<double> m4 = new double(5.1);
    //std::cout << *m4 << std::endl;

    return 1;
}

后记

智能指针的学习就先到这里。下一篇记录一下普通指针的使用。

上一篇:Lesson3


下一篇:C++弱引用智能指针weak_ptr的用处