#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

C++ 几种智能指针的简单实现相关推荐

  1. C++智能指针及其简单实现

    原文:http://www.cnblogs.com/xiehongfeng100/p/4645555.html C++智能指针及其简单实现 本文将简要介绍智能指针shared_ptr和unique_p ...

  2. 【C++ 语言】智能指针 引入 ( 内存泄漏 | 智能指针简介 | 简单示例 )

    文章目录 I . 智能指针 引入 II . 智能指针 简介 III . 智能指针 简单示例 I . 智能指针 引入 1 . 示例前提 : 定义一个 Student 类 , 之后将该类对象作为智能指针指 ...

  3. C++ STL 四种智能指针

    文章目录 0.前言 1.unique_ptr 2.auto_ptr 3.shared_ptr 3.1 shared_ptr 简介 3.2 通过辅助类模拟实现 shared_ptr 4.weak_ptr ...

  4. C++ — 智能指针的简单实现以及循环引用问题

    http://blog.csdn.net/dawn_sf/article/details/70168930 智能指针 _________________________________________ ...

  5. C++的4种智能指针剖析使用

    1. 智能指针背后的设计思想 我们先来看一个简单的例子: void remodel(std::string & str) {std::string * ps = new std::string ...

  6. C++ 智能指针的简单原理

    C++ 智能指针的简单原理 为什么会有智能指针的原因 delete引起的内存泄漏 智能指针的使用及其原理 RAII auto_ptr std::unique_ptr std::shared_ptr(线 ...

  7. C++智能指针(二)模拟实现三种智能指针

    https://blog.csdn.net/nou_camp/article/details/70186721 在上一篇博客中提到了Auto_ptr(C++智能指针(一)),下面进行模拟实现Auto_ ...

  8. C++智能指针(一)智能指针的简单介绍

    https://blog.csdn.net/nou_camp/article/details/70176949 C++智能指针  在正式了解智能指针前先看一下下面的一段代码 #include<i ...

  9. C++ 四种智能指针详解

    智能指针出现的原因:主要解决的是堆内存分配释放,忘记释放内存引发的内存泄漏问题,智能指针最主要的事情就是让程序员无需去注意内存释放,内存释放的问题放在智能指针内部进行处理. 智能指针有四种,包括aut ...

最新文章

  1. [项目过程中所遇到的各种问题记录]部署篇——项目部署过程中那些纠结的问题-SQLServer...
  2. hitTest和pointInside如何响应用户点击事件
  3. MySQL中的二进制类型
  4. Quarkus 0.12.0 发布,下一代 K8s 原生 Java 框架
  5. Coding: 一亿个数找最大的1000个数
  6. Java 集合系列(一)
  7. mysql查询重复数据
  8. Lumia 800 升级 windows phone 7.8
  9. linux 进程0 写时复制,linux 写时复制 COW 过程梳理
  10. cvEqualizeHist() 直方图均衡化(多通道彩图)
  11. 网络安全界基于知识的识别和映射提出网络空间资源分类明细
  12. Marlin2.0.7的configuration.h中文说明
  13. Heterogeneous Treatment Effect
  14. 优酷网(Youku.com)架构经验
  15. CSS性能优化的几个技巧
  16. 电脑网络重置后如何连接网络
  17. 2022山东艾灸展,济南中医艾灸展,艾制品展,中国艾灸仪器展
  18. .NET ZXING 生成带logo的二维码和普通二维码及条型码
  19. java如何判断一个点在一条线段上
  20. 首设农作物种业专区农民丰收节国际贸易促进会舌尖上进博会

热门文章

  1. 正则表达式隐藏手机号、身份证号、台胞证、护照、回乡证中间几位数字信息
  2. 域名注册、域名实名认证、域名解析流程详解
  3. jQuery写法 入口函数
  4. mysql order field_mysql 使用order by filed,locate和instr自定义排序
  5. montypython买火柴_python nltk 笔记(持续更新)
  6. 【脚本】网页端微信读书书架中书籍详细信息
  7. python test suite什么意思_如何:在python中设置testsuite
  8. mac数字键盘错乱_苹果笔记本数字键盘打不出数字怎么办_苹果笔记本按不出数字如何解决-win7之家...
  9. 京东运营 不错的帖子
  10. linux系统连接校园无线网卡,Linux连接校园网