C++ 几种智能指针的简单实现

#pragma once

// 智能指针 

// 定义个类来封装资源的分配和释放,在构造 函数完成资源的分配和初始化,在析构函数完成资源的

// 清理,可以 保证资源的正确初始化和释放。

// 这里简单实现 AutoPtr、 ScopedPtr、ScopedArray以及 SharedPtr


 //------------------------------SmartPtr.h-------------------

template<typename T>

class AutoPtr //缺点 定义多个指向同一空间的ptr 只有一个控制 其他的都失效了 

{

public:

    AutoPtr(T* ptr = NULL)

        :_ptr(ptr)

    {}


    AutoPtr(AutoPtr<T>& ap)// 这里没有用const 为了修改ap的成员

        :_ptr(ap._ptr)

    {

        ap._ptr = NULL;// 只能有一个智能指针 指向空间 (控制权

    }

    

    AutoPtr<T>& operator= (AutoPtr<T>& ap)

    {

        if(_ptr != ap._ptr)//排除 1 自赋值 2(常常会忽略) 虽然不是自赋值 但两个的_ptr 指向同一空间

        {

            //第3种情况 两个不指向同一空间

            delete _ptr;

            _ptr = ap._ptr;

            ap._ptr = NULL;


            return *this;

        }

    }


    ~AutoPtr()

    {

        if(_ptr)

        {

            cout<<"delete _ptr"<<_ptr<<endl;

            delete _ptr;

        }

    }


    T& operator*()

    {

        return *_ptr;

    }

    // 从原理来说 要两个-> 

    // operator->()返回的是T* 再->才能访问对应成员

    // 这里编译器做了处理

    // 如 operator++() operator++(int)

    T* operator->()

    {

        return _ptr;

    }


protected:

    T* _ptr;

};


void testAutoPtr()

{


    struct A

{

    int _a;

};


    AutoPtr<int> ap1(new int(1));

    AutoPtr<int> ap2(ap1);

    AutoPtr<int> ap3(new int(2));

    ap3 = ap2;


    *ap3 = 10;//运算符重载T& operator*()


    A* p4 = new A;

    p4->_a = 10;


    AutoPtr<A> ap4(new A);//运算符重载 T* operator->()

    ap4->_a = 4;

}



//  AutoPtr 的老版本的写法 比之前的多了一个bool 类型的_owner

// 缺点 : 在 

// AutoPtr<int> ap1(new int (1)); 

//if (1)

// {

//        AutoPtr<int> ap2(ap1);

// }

// 这种场景下 ap2出了作用域 析构 释放空间 但ap1指针还指向那块空间 很危险(野指针)


template<typename T>

class AutoPtr

{

public:

AutoPtr(T* ptr = NULL)

        :_ptr(ptr)

    {}


AutoPtr(AutoPtr<T>& ap)

{

_ptr = ap._ptr;

_owner = true;

ap._owner = false;

}


~AutoPtr()

{

if (_owner)

{

delete _ptr;

_owner = false;

}

}


AutoPtr<T>& operator=(AutoPtr<T>& ap)

    {

        if(_ptr != ap._ptr)//排除 1 自赋值 2(常常会忽略) 虽然不是自赋值 但两个的_ptr 指向同一空间

        {

            //第3种情况 两个不指向同一空间

if (_owner == true)

{

delete _ptr;

}

_ptr = ap._ptr;

ap._owner = false;

_owner = true;

            return *this;

        }

    }


 

    T& operator*()

    {

        return *_ptr;

    }


T* operator->()

    {

        return _ptr;

    }


protected:

T* _ptr;

bool _owner;


};


void testAutoPtr()

{


    struct A

{

int _a;

};


    AutoPtr<int> ap1(new int(1));

    AutoPtr<int> ap2(ap1);

    AutoPtr<int> ap3(new int(2));

    ap3 = ap2;


    *ap3 = 10;//运算符重载T& operator*()


    A* p4 = new A;

    p4->_a = 10;


    AutoPtr<A> ap4(new A);//运算符重载 T* operator->()

    ap4->_a = 4;

}

//-----------------------------------------------------

template<typename T>

class ScopedPtr //缺点 不能解决 两个对象之间的拷贝 

{

public:

    ScopedPtr(T* ptr = NULL)

        :_ptr(ptr)

    {}


    ~ScopedPtr()

    {

        if (_ptr)

        {

            cout<<"delete:"<<_ptr<<endl;

            delete _ptr;

        }

    }


    T& operator*()

    {

        return *_ptr;

    }


    T* operator->()

    {

        return _ptr;

    }


    //与AutoPtr相比 简单 粗暴 直接加protected:防止拷贝构造和赋值重载 同时也防止别人在类外实现

protected:

    ScopedPtr(ScopedPtr<T>& sp);

    ScopedPtr<T>& operator=(ScopedPtr<T>& sp);


protected:

    T* _ptr;

};


void TestScopedPtr()

{

    ScopedPtr<int> sp1(new int(1));

   // ScopedPtr<int> sp2(sp1);

}


//------------------------------------------

template<typename T>

class SharedPtr

{

public:

    SharedPtr(T* ptr = NULL)

        :_ptr(ptr)

        ,_pCount(new long(1))

    {}


    ~SharedPtr()

    {

        _Release();

    }


    SharedPtr(const SharedPtr<T>& sp)

        :_ptr(sp._ptr)

        ,_pCount(sp._pCount)

    {

        ++(*_pCount);

    }

/************************************

   SharedPtr<T>& operator=(const SharedPtr<T>& sp)

   {

       // 考虑多种情况

       // 1 sp1 = sp1

       // 2 sp1 = sp2; ==>sp1,sp2管理着同一块内存

       // 3 sp1 = sp3 sp1与sp3 指向的空间不同


       if (_ptr != sp._ptr)//排除1、 2

       {

  _Release();


  _ptr = sp._ptr;

  _pCount = sp._pCount;

  (*_pCount)++;

       }


        return *this;

   }

   ***************************************/


SharedPtr<T>& operator=(SharedPtr<T> sp)//不用引用 不用const

   {

      //现代 写法

  swap(_ptr, sp._ptr);

  swap(_pCount, sp._pCount);


        return *this;

   }

wKiom1b9FuCCs3CyAAHZbScBavs620.bmp


   T& operator*()

   {

return *_ptr;

   }


   T* operator->()

   {

return _ptr;

   }


   long UseCount()

   {

return *_pCount;

   }


   T* GetPtr()

   {

return _ptr;

   }



protected:

void _Release()

{

if(--(*_pCount) == 0)

{

delete _ptr;

delete _pCount;

}

}


protected:

    T* _ptr;

    long* _pCount;

};


void TestSharedPtr()

{

    SharedPtr<int> sp1(new int(1));

    SharedPtr<int> sp2(sp1);

    SharedPtr<int> sp3(sp1);


   // int a;

   // const int* p = &a;

    int const * p = &a;

   // // error: (*p) = 1; 要是可修改的左值

   // // p = &a;

    int * p2 = p; // error  不能从const到非const


   // int * const p3 = &a;

   error  p3 = &a;要是可修改的左值

   // *p3 = 5;


cout<<"sp1:"<<sp1.UseCount()<<endl;

cout<<"sp2:"<<sp2.UseCount()<<endl;

cout<<"sp3:"<<sp3.UseCount()<<endl<<endl;


sp1 = sp1;

sp1 = sp2;


cout<<"sp1:"<<sp1.UseCount()<<endl;

cout<<"sp2:"<<sp2.UseCount()<<endl;

cout<<"sp3:"<<sp3.UseCount()<<endl<<endl;


SharedPtr<int> sp4(new int(2));

sp1 = sp4;


cout<<"sp1:"<<sp1.UseCount()<<endl;

cout<<"sp2:"<<sp2.UseCount()<<endl;

cout<<"sp3:"<<sp3.UseCount()<<endl;

cout<<"sp4:"<<sp4.UseCount()<<endl;


}


//-----------------------------------------------------

template<typename T>

class ScopedArray

{

public:

ScopedArray(T* ptr = NULL)

:_ptr(ptr)

{}


~ScopedArray()

{

if (_ptr)

{

delete[] _ptr;

}

}


/*T& operator*()

{

return *_ptr;

}


T* operator->()

{

return _ptr;

}*/

//不需要重载上面两个 用operator[]


T& operator[](size_t index)

{

return _ptr[index];

}

protected:

ScopedArray(const ScopedArray<T>& sp);

ScopedArray<T>& operator=(const ScopedArray<T>& sp);


protected:

T* _ptr;

};


void TestScopedArray()

{

struct V

{

int _v;

};


ScopedArray<V> sa(new V[10]);

sa[0]._v = 1;

sa[2]._v = 11;

}


//-----------------------------test.cpp--

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>

using namespace std;


#include "SmartPtr.h"


//void Test1()

//{

//    int* p = new int(1);

//

//    if (1)

//    {

//        delete p;

//

//        return;

//    }

//    delete p;

//}

//void DoSomething()

//{

//    if (1)

//    {

//        throw 1;

//    }

//}

//

//void Test2()

//{

//    int* p = new int(1);

//    try

//    {

//        DoSomething();

//    }

//    catch(...)

//    {

//        delete p;

//        throw;

//    }

//

//    delete p;

//}

//

//void Test1()

//{

//    int* p = new int(1);

//    AutoPtr<int> ap(p);

//    if (1)

//    {

//       // delete p;

//

//        return;

//    }

//   // delete p;

//}

//void DoSomething()

//{

//    if (1)

//    {

//        throw 1;

//    }

//}

//

//void Test2()

//{

//    int* p = new int(1);

//    AutoPtr<int> ap(p);

//

//    DoSomething();

//    /*try

//    {

//        DoSomething();

//    }

//    catch(...)

//    {

//        delete p;

//        throw;

//    }

//

//    delete p;*/

//}

//

//int main()

//{

//    try

//    {

//        Test1();

//        Test2();

//    }

//    catch(...)

//    {

//        cout<<"未知异常"<<endl;

//    }

//

//    getchar();

//    return 0;

//}





int main()

{

    

    //TestSharedPtr();


TestScopedArray();


getchar();

    return 0;

}

//==================================

//==================================

//==================================

//

//1、 增加AutoPtr的另一种写法(老版本写法)

//2、 模拟SharedPtr的定置删除器

//3、 定置删除器和循环引用的场景并理解


// 智能指针 使用库中的 



#include <memory> // 这个头文件包含 auto_ptr 、unique_ptr 、shared_ptr

using namespace std;


void test_auto_ptr()

{

//auto_ptr 用到 memory头文件

auto_ptr<int> ap1(new int(1));

auto_ptr<int> ap2(ap1);

}


// scoped_ptr 在 C++ 11 中叫 unique_ptr

void test_scoped_ptr()

{

unique_ptr<int> sp1(new int(1));

// error unique_ptr<int> sp2(sp1);

}


void test_shared_ptr1()

{

shared_ptr<int> sp1(new int (1));

cout<<"sp1:"<<sp1.use_count()<<endl;

shared_ptr<int> sp2(sp1);

cout<<"sp1:"<<sp1.use_count()<<endl;

cout<<"sp2:"<<sp2.use_count()<<endl;

}


//--------------------------------------------------

void test_shared_ptr2()

{

struct Node

{

//Node* _next;

//Node* _prev;

shared_ptr<Node> _next; // 容易引起循环引用 解决方法详见 下面weak_ptr

shared_ptr<Node> _prev;

~Node()

{

cout<<"delete:"<<this<<endl;

}

};

//  循环引用问题 这几步都用的是 智能指针 cur next _next _prev

shared_ptr<Node> cur(new Node());

shared_ptr<Node> next(new Node());

// 没有下面两句就可以释放的 下面两句引起循环引用

// *********重点***********

//cur->_next = next;

//next->_prev = cur;

// 分析 循环引用 原因 图


wKioL1cFIJWCmTltAACqczONHcA770.png

}


// 解决循环引用问题 weak_ptr


void test_shared_ptr3()

{

struct Node

{

//Node* _next;

//Node* _prev;

/*shared_ptr<Node> _next;

shared_ptr<Node> _prev;*/

// 解决循环引用 (运用弱指针weak_ptr 不增加shared_ptr的count 增加自己weak_ptr 的引用计数 count)

//weak_ptr 重载了operator->() operator*()

// weak_ptr 唯一的目的 就是解决shared_ptr的死穴 循环引用问题 

// wead_ptr不能单独使用 例如没有weak_ptr<int> (int*)类型的构造函数 只有weak_ptr<shared_ptr> (shared_ptr&)

// 用弱指针 场景 内部含有指向对方的 智能指针

weak_ptr<Node> _next;

weak_ptr<Node> _prev;



~Node()

{

cout<<"delete:"<<this<<endl;

}

};

//  循环引用问题 这几步都用的是 智能指针 cur next _next _prev

shared_ptr<Node> cur(new Node());

shared_ptr<Node> next(new Node());

cout<<"cur"<<cur.use_count()<<endl;

cout<<"next:"<<next.use_count()<<endl;

// *********重点**** weak_ptr解决循环引用问题 *******

cur->_next = next;

next->_prev = cur;

cout<<"cur"<<cur.use_count()<<endl;

cout<<"next:"<<next.use_count()<<endl;


}

wKioL1cFIWXBTDMaAAERVnah6ng378.png

//--------------------------------------------------------------------

// 仿函数

// 原理: 重载operator() ()

// 使用: 用Less创建一个结构体对象less

// 使用less() 看起来像函数调用 其实是使用了对象的operator()操作 这样传参传如一个less对象就能用它的对应的operator()方法 这样就能定制删除器了

template<typename T>

struct Less 

{

bool operator() (const T& L, const T& R)

{

return L < R;

}

};


void test_less()

{

Less<int> less;

cout<<less(1, 2)<<endl;

}


//------------------------------

//模拟SharedPtr的定置删除器

void test_shared_ptr4()

{

//场景1 没问题

int* p1 = (int*)malloc(sizeof(int) * 10);

shared_ptr<int> sp1(p1);


// 场景2  析构出错 不能将FILE* 转换为int*

//FILE* p2 = fopen("test.txt", "r");

//shared_ptr<int> sp2(p2);

}


// 定制删除器

struct Free

{

void operator()(void* ptr)

{

cout<<"Free:"<<ptr<<endl;

free(ptr);

}

};


struct FileClose //场景2的 删除器

{

void operator()(void* fp)

{

cout<<"FileClose:"<<fp<<endl;

if (fp != NULL)

{

fclose((FILE*)fp);

}

}

};


void test_Free()

{

//场景1 没问题

int* p1 = (int*)malloc(sizeof(int) * 10);

// ***********  重点 定制删除器的应用

// Free() 创建一个匿名对象

shared_ptr<int> sp1(p1, Free()); // 重点 【给库中的 shared_ptr 传入 Free()的匿名对象】 下边改进的自己的SharedPtr也用到这方法


// 场景2  析构出错 不能将FILE* 转换为int*

// 定制删除器后不出错

FILE* p2 = fopen("test.txt", "r");

shared_ptr<FILE> sp2(p2, FileClose());

}

//---------------------------------


//用定制删除器 改进 之前的SharedPtr

template<typename T, typename D = DefaultDel<T>>//D 是删除器结构体类型

class SharedPtr

{

public:

    SharedPtr(T* ptr = NULL)

        :_ptr(ptr)

        ,_pCount(new long(1))

    {}


SharedPtr(T* ptr, D del)

:_ptr(ptr)

,_pCount(new long(1))

,_del(del)

{}


    ~SharedPtr()

    {

        _Release();

    }


    SharedPtr(const SharedPtr<T, D>& sp)

        :_ptr(sp._ptr)

        ,_pCount(sp._pCount)

    {

        ++(*_pCount);

    }



SharedPtr<T, D>& operator=(SharedPtr<T,D> sp)//不用引用 不用const

   {

      //现代 写法

  swap(_ptr, sp._ptr);

  swap(_pCount, sp._pCount);


        return *this;

   }


   T& operator*()

   {

return *_ptr;

   }


   T* operator->()

   {

return _ptr;

   }


   long UseCount()

   {

return *_pCount;

   }


   T* GetPtr()

   {

return _ptr;

   }



protected:

void _Release()

{

if(--(*_pCount) == 0)

{

//delete _ptr;

//********更换成——del()************

_del(_ptr);

delete _pCount;

}

}


protected:

    T* _ptr;

    long* _pCount;

D _del;

};


// 删除器

template<typename T>

struct DefaultDel

{

void operator()(T* ptr)

{

delete ptr;

}

};

template<typename T>

struct FreeShared

{

void operator()(T* ptr)

{

free(ptr);

}

};


void TestDeleter()

{

SharedPtr<int, DefaultDel<int>> sp1(new int(10));

SharedPtr<int, FreeShared<int>> sp2((int*)malloc(sizeof(int) * 2));


SharedPtr<int> sp3(new int(1));

}


//-----------------------------------------------------


#include "SmartPtr.h"

int main()

{

//test_auto_ptr();

//test_shared_ptr4();

//test_less();

test_Free();

//TestDeleter();


getchar();

return 0;

}


本文出自 “城市猎人” 博客,请务必保留此出处http://alick.blog.51cto.com/10786574/1758966

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值