C++智能指针

1 智能指针是什么?智能指针的原理

a smart pointer is a class template that you declare on the stack, and initialize by using a raw pointer that points to a heap-allocated object. After the smart pointer is initialized, it owns the raw pointer. This means that the smart pointer is responsible for deleting the memory that the raw pointer specifies. The smart pointer destructor contains the call to delete, and because the smart pointer is declared on the stack, its destructor is invoked when the smart pointer goes out of scope, even if an exception is thrown somewhere further up the stack.

                                                                                Smart pointers (Modern C++) | Microsoft Docs

智能指针是一个模板类,这个类的构造函数传入一个普通的指针,析构函数释放传入的指针。智能指针上的类都是栈上的对象,所以当函数或者程序结束时就会自动释放。

2 常用智能指针

  • unique_ptr 

        unique_ptr实现独占式拥有或严格拥有概念,保证同一时间内只有一个智能指针可以指向该对象。unique_ptr支持不可复制,赋值,但可以move()转移对象的所有权,局部变量的返回值除外

unique_ptr实现重点:

  • 移动构造、移动赋值问题
  • 阻止拷贝构造与拷贝赋值
template<class T>
class myUniquePtr{
private:
    T *m_ptr;
public:
    explicit myUniquePtr(T* ptr= nullptr):m_ptr(ptr) {}
    ~myUniquePtr(){
        if(m_ptr)
            delete m_ptr;
    }
    myUniquePtr(const myUniquePtr&) = delete;
    myUniquePtr& operator=(const myUniquePtr &p) =delete;
    T* operator*() const{return *m_ptr;}
    T& operator->() const{return m_ptr;}
    myUniquePtr(myUniquePtr &&p):m_ptr(p.m_ptr){p.m_ptr= nullptr;}
    myUniquePtr& operator=(myUniquePtr &&p){
        swap(*this,p);//采用swap函数实现移动赋值
        return *this;
    }
    explicit operator bool() const {return m_ptr;}
    void reset(T* q = nullptr){
        if(q!=m_ptr){
            if(m_ptr)
                delete m_ptr;
            m_ptr = q;
        }
    }
    T* release(){
        T* res = m_ptr;
        m_ptr = nullptr;
        return res;
    }
    T* get(){
        return m_ptr;
    }
    void swap(myUniquePtr &p){
        std::swap(m_ptr,p.m_ptr);
    }
};
  • shared_ptr

        shared_ptr 是引用计数型(reference counting)智能指针,几乎所有的实现都采用在堆(heap)上放个计数值(count)的办法。具体来说,shared_ptr<Foo> 包含两个成员,一个是指向 Foo 的指针 ptr,另一个是 ref_count 指针,指向堆上的 ref_count 对象,ref_count 对象有多个成员。

        shared_ptr是否线程安全,如何实现线程安全?

        结论:多个线程同时读同一个shared_ptr对象是线程安全的,但是如果是多个线程对同一个shared_ptr对象进行读和写,则需要加锁。

        为什么尽可能使用make_shared()?      

        为了节省一次内存分配,原来 shared_ptr<Foo> x(new Foo); 需要为 Foo 和 ref_count 各分配一次内存,现在用 make_shared() 的话,可以一次分配一块足够大的内存,供 Foo 和 ref_count 对象容身。

Shared_ptr实现:

template<class T>
class mySharePtr{
public:
    explicit mySharePtr(T *p= nullptr):m_ptr(p){
        m_count = new unsigned int(0);
        ++(*m_count);
    }
    ~mySharePtr(){
        --(*m_count);
        if((*m_count)==0){
            delete []m_ptr;
            m_ptr = nullptr;
            delete []m_count;
            m_count = nullptr;
        }
    }
    mySharePtr(const mySharePtr<T>& other){
        m_ptr = other.m_ptr;
        m_count = other.m_count;
        ++(*m_count);
    }
    mySharePtr<T> operator=(const mySharePtr<T>& other){
        // 防止自身赋值
        ++(*other.m_count);
        --(*m_count);
        if((*m_count)==0){
            delete []m_ptr;
            m_ptr = nullptr;
            delete []m_count;
            m_count = nullptr;
        }
        m_ptr = other.m_ptr;
        m_count = other.m_count;
        return *this;
    }
    T* operator*() const{
        return m_ptr;
    }
    T& operator->()const{
        return *m_ptr;
    }
private:
    T* m_ptr;
    unsigned int* m_count;
};
  • weak_ptr                 

        shared_ptr存在互相引用形成环的问题,这样子两个指针指向的内存都无法释放,需要手动打破循环引用或者是使用weak_ptr。weak_ptr是一个弱引用,只引用不计数。如果一块内存被shared_ptr和weak_ptr同时引用,当所有shared_ptr析构之后,不管还有没有weak_ptr应用该内存,内存都会被释放掉。所以weak_ptr不保证其指向的内容是有效的,在使用前需要检查weak_ptr是否为空指针。

参考资料 

shared_ptr的线程安全性 - gqtc - 博客园

C++11智能指针(五):shared_ptr的循环引用的问题及weak_ptr_小麒麟的成长之路-CSDN博客                                                                                                   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值