C++ 之实现自己的 shared_ptr

            /*shared_ptr.h 文件*/
/*********************************************************
    > File Name: shared_ptr.h
    > Author: Liu Shengxi 
    > Mail: 13689209566@163.com
    > Created Time: 2018年06月05日 星期二 15时35分48秒
 *****************************************************/

#ifndef _SHARED_PTR_H
#define _SHARED_PTR_H

template<typename> class shared_ptr ;

template< class T >
void swap( shared_ptr<T>& lhs, shared_ptr<T>& rhs ) noexcept 
{
    std::cout << "swap out object  " << std::endl ;
    lhs.swap(rhs);
}

template<typename T>
class shared_ptr {
    using DelFuncPtr = void (*)(T*) ;

public:
    shared_ptr():m_ptr(nullptr),
    count_ptr( new size_t(0)),del(nullptr)
    {
    }
    explicit shared_ptr(T *ptr ,DelFuncPtr temp = nullptr ):
    m_ptr(ptr),count_ptr(new size_t(1)), del(temp )
    { 
    }
    //拷贝构造函数
    shared_ptr(const shared_ptr &hp):
    m_ptr(hp.m_ptr),count_ptr(hp.count_ptr),del(hp.del)
    { 
        ++(*count_ptr) ; //引用计数加1 
    }
    //拷贝赋值运算符 
    shared_ptr& operator=( shared_ptr &rhs){
        swap(*this,rhs);
        return *this;
    }
    //析构函数
    ~shared_ptr(){
        --(*count_ptr);
        if((*count_ptr) == 0 ){
            del ? del(m_ptr):
                delete m_ptr;
                delete count_ptr  ;
        }
        m_ptr = nullptr ;
        count_ptr =nullptr ;
    }
    size_t use_count(){ return (*count_ptr);}
    T& operator*() { return *m_ptr ;}
    T* operator->() { return m_ptr ; }

    void swap(shared_ptr &hp){
        std::cout << "swap in object " << std::endl ;
        using std::swap ;
        swap(m_ptr,hp.m_ptr);
        swap(count_ptr,hp.count_ptr);
        swap(del,hp.del);
    }
    void reset( ){
        if((*count_ptr) == 1) {
            delete m_ptr;
            delete count_ptr ;
            m_ptr = nullptr ;
            count_ptr =nullptr ;
        }
    }
    void reset( T *hp ,DelFuncPtr del = nullptr ){
        shared_ptr temp(hp,del);
        swap(temp);
    }
private:
    T* m_ptr = nullptr ;
    size_t* count_ptr = nullptr ;
    //思考一下为什么是size_t*,而不是 size_t ? ?
    DelFuncPtr del = nullptr ; //自定义的删除器
};
#endif
                    /*main.cpp 文件*/
/*************************************************************************
    > File Name: main.cpp
    > Author: Liu Shengxi 
    > Mail: 13689209566@163.com
    > Created Time: 2018年06月05日 星期二 15时39分58秒
 ************************************************************************/

#include <iostream>
#include"shared_ptr.h"
using namespace std ;
struct Foo {
    Foo() { std::cout << "Foo()\n"; }
    ~Foo() { std::cout << "~Foo()\n"; }
    Foo(const Foo&) { std::cout << "Foo copy ctor\n"; }
    Foo(Foo&&) { std::cout << "Foo move ctor\n"; }
};

struct Fooo {
    Fooo(int n = 0) noexcept : bar(n) { std::cout << "Fooo: constructor, bar = " << bar << '\n'; }
    ~Fooo() { std::cout << "Fooo: destructor, bar = " << bar << '\n'; }
    int GetBar() const noexcept { return bar; }

private:
    int bar;
};

struct D {
    void bar() { std::cout << "Call deleter D::bar()...\n"; }
    void operator()(Foo* p) const
    {
        std::cout << "Call delete from function object...\n";
        delete p;
    }
};
int main()
{
std::cout << "shared_ptr constructor with no managed object\n";
    {
        shared_ptr<Foo> sh1;
    }

    std::cout << "shared_ptr constructor with object and test swap \n";
    {
        shared_ptr<Foo> sh2(new Foo);
        std::cout << sh2.use_count() << '\n';//1
        shared_ptr<Foo> sh3(sh2);
        std::cout << sh3.use_count() << '\n';// 2

        shared_ptr<int> sh4(new int(4444)) ;
        shared_ptr<int> sh5(new int(5555)) ; // test swap()  
        sh4.swap(sh5);
        cout << "sh4 == "  << *sh4 << "\nsh5 == " << *sh5 << endl ; // 5555 4444 
        swap(sh4,sh5);
        cout << "sh4 == "  << *sh4 << "\nsh5 == " << *sh5 << endl ;  //4444  5555
    }

    std::cout << "shared_ptr constructor with deleter\n";
    {
        shared_ptr<Foo> sh5(new Foo, [](Foo* p) {
            std::cout << "Call delete from lambda...\n";
            delete p;
        });
    }

    {
        shared_ptr<Fooo> sptr(new Fooo(111)) ;
        std::cout << "The first Fooo's bar is " << sptr->GetBar() << "\n"; // 111  
        sptr.reset(new Fooo); //先搞一个新的出来,然后干掉原来的,避免自赋值
        std::cout << "The second Fooo's bar is " << sptr->GetBar() << "\n"; // 0 
    }
}

运行结果:
这里写图片描述

总结:

  1. 什么是size_t 类型
    它是一个与机器相关的unsigned类型,其大小足以保证存储内存中对象的大小。一般用作下标类型 。
  2. 为什么是size_t*,而不是 size_t ? ?

因为你要定义的是行为像指针的类而不是像值的类,在多个指针共同指向同一个对象时,只需要拷贝指针,利用指针让它引用计数加一就可以了。如果一个指针被析构时,也是通过指针让引用计数减一即可。

如果为size_t类型的成员变量,在多个shared_ptr对象指向同一资源时,其中一个shared_ptr对象析构了count_ptr = count_ptr -1,但是不会影响到其他shared_ptr对象。所以使用size_t* 来达到多个shared_ptr对象指向同一资源的能够共享count_ptr 的目的。

3 . 另外注意删除器的书写方式和成员函数swap与友元函数swap的书写即可

posted @ 2018-06-06 18:01  Tattoo_Welkin  阅读(215)  评论(0编辑  收藏  举报