您的位置:首页 > 编程语言 > C语言/C++

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

2016-10-25 14:01 330 查看
#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;
   }




   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;
// 分析 循环引用 原因 图




}

// 解决循环引用问题 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;

}



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

// 仿函数
// 原理: 重载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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: