说起智能指针,不少人都不陌生。比方auto_ptr、shared_ptr、unique_ptr、weak_ptr。

依据shared_ptr的功能,自己仿造也实现了个。

对于shared_ptr这样的智能指针,有一个共享的引用计数器来控制指针对象的销毁,当引用计数器变为0时。则销毁指针指向的对象。对于多线程安全问题,我在代码中使用的Interlocked系列的原子操作函数。

在学习过程中,渐渐学会了RAII(Resource Acquisition Is Initialization),慢慢领略到了这样的模式的优点。

直接上代码:

SmartPtr.hpp

#pragma once
#include "stdafx.h"
#include <assert.h>
#include <windows.h> //#define DEBUG_SMARTPTR template<typename T>
class SmartPtr; template <typename T>
class RefPtr
{
friend class SmartPtr<T>;
explicit RefPtr(T *p) :pointer(p), nUse(0)
{
assert(pointer);
#ifdef DEBUG_SMARTPTR
std::cout << "Create Pointer!" << std::endl;
#endif
} RefPtr(const RefPtr&)
{ } RefPtr& operator= (const RefPtr & ref)
{ } ~RefPtr()
{
#ifdef DEBUG_SMARTPTR
std::cout << "Delete Pointer!" << std::endl;
#endif
assert(pointer);
if (pointer != NULL)
{
delete pointer;
pointer = NULL;
}
} unsigned int AddRefCount()
{
return InterlockedIncrement((unsigned int*)&nUse);
} unsigned int SubRefCount()
{
return InterlockedDecrement((unsigned int*)&nUse);
} bool AddRefCount_lock()
{
for (;;)
{
unsigned int temp = nUse;
if (temp == 0)
{
return false;
}
if (InterlockedCompareExchange((unsigned int *)&nUse, temp + 1, temp) == temp)
{
return true;
}
}
} volatile unsigned int nUse;
T *pointer;
}; template<typename T>
class SmartPtr
{
public:
explicit SmartPtr(T *pointer) :ptr(new RefPtr<T>(pointer))
{
assert(pointer);
#ifdef DEBUG_SMARTPTR
std::cout << "Create SmartPointer!" << std::endl;
#endif
ptr->AddRefCount();
} explicit SmartPtr(const SmartPtr<T>& sp) :ptr(sp.ptr)
{
#ifdef DEBUG_SMARTPTR
std::cout << "Copy0 SmartPointer!" << std::endl;
#endif
ptr->AddRefCount();
} explicit SmartPtr(const SmartPtr<T>* sp) :ptr(sp->ptr)
{
#ifdef DEBUG_SMARTPTR
std::cout << "Copy1 SmartPointer!" << std::endl;
#endif
ptr->AddRefCount();
} SmartPtr& operator=(const SmartPtr<T>& sp)
{
if (sp.ptr != ptr)
{
//注意先加后减,防止指向同对象析构的问题
if (sp.ptr->AddRefCount_lock())
{
if (ptr->SubRefCount() == 0)
{
delete ptr;
}
ptr = sp.ptr;
}
}
#ifdef DEBUG_SMARTPTR
std::cout << "Copy2 SmartPointer!" << std::endl;
#endif
return *this;
} T* operator->()
{
return GetPtr();
} T* operator->() const
{
return GetPtr();
} T& operator*()
{
return *ptr->pointer;
} T& operator*() const
{
return *ptr->pointer;
} bool operator!()
{
return !ptr;
} ~SmartPtr()
{
if (ptr->SubRefCount() == 0)
{
delete ptr;
}
#ifdef DEBUG_SMARTPTR
std::cout << "Delete SmartPointer!" << std::endl;
#endif
} int GetRefCount() const
{
return ptr->nUse;
} bool isNull()
{
return ptr->pointer == NULL;
} T* GetPtr() const
{
assert(ptr->pointer);
return ptr->pointer;
} //返回对象
T GetValue() const
{
assert(ptr->pointer);
return *ptr->pointer;
} private:
RefPtr<T> *ptr;
}; //兼容const比較
template<typename T>
inline bool operator==(const SmartPtr<T>& a,const SmartPtr<T>& b)
{
return a.GetPtr() == b.GetPtr();
}
template<typename T>
inline bool operator!=(const SmartPtr<T>& a,const SmartPtr<T>& b)
{
return a.GetPtr() != b.GetPtr();
}

test.cpp

#include "SmartPtr.hpp"
#include <iostream>
#include <process.h> #define THREADCOUNT 10 typedef struct _PERSON_
{
char szName[20];
int nAge;
~_PERSON_()
{
std::cout << "Person Distructor!"<< std::endl;
}
}PERSON; SmartPtr<PERSON> g_p(new PERSON{ "g_test", 12 }); unsigned int __stdcall testThread(void *pParam)
{
SmartPtr<PERSON> sp((SmartPtr<PERSON> *)pParam);
g_p = sp;
std::cout << sp->nAge << std::endl;
return 0;
} int _tmain(int argc, _TCHAR* argv[])
{
do
{
HANDLE hThread[THREADCOUNT];
SmartPtr<PERSON> p0(new PERSON{ "Jovi", 12 });
SmartPtr<PERSON> p1(new PERSON{ "Solanin", 13 }); SmartPtr<PERSON> p2(p1);
const SmartPtr<PERSON> p3(p1); SmartPtr<PERSON> p4(p3);
std::cout << (p3 == p1) << std::endl;
std::cout << (p2 == p0) << std::endl;
std::cout << (p3 != p1) << std::endl;
std::cout << (p2 != p0) << std::endl;
p4 = p0;
SmartPtr<PERSON> *p = new SmartPtr<PERSON>(p1);
for (int i = 0; i < THREADCOUNT; i++)
{
hThread[i] = (HANDLE)_beginthreadex(NULL, 0, testThread, (void *)p, 0, 0);
// WaitForSingleObject(hThread[i], INFINITE);
}
WaitForMultipleObjects(THREADCOUNT, hThread, TRUE, INFINITE);
delete p;
} while (0); system("pause");
return 0;
}

此处的do while(0)仅仅是我想在pause前打印出全部析构函数的输出。

对于基于引用计数器的智能指针,最致命缺点就是循环引用,导致对象被长期占用,无法释放。

以上是我对智能指针的实现和个人看法,如有不对的地方,欢迎指出。

C++智能指针的实现的更多相关文章

  1. enote笔记法使用范例(2)——指针(1)智能指针

    要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...

  2. C++11 shared_ptr 智能指针 的使用,避免内存泄露

    多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...

  3. C++智能指针

    引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...

  4. EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针

    一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...

  5. 智能指针shared_ptr的用法

    为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...

  6. 智能指针unique_ptr的用法

    unique_ptr是独占型的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,如下面错误用法: std::unique_pt ...

  7. 基于C/S架构的3D对战网络游戏C++框架 _05搭建系统开发环境与Boost智能指针、内存池初步了解

    本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...

  8. C++ 引用计数技术及智能指针的简单实现

    一直以来都对智能指针一知半解,看C++Primer中也讲的不够清晰明白(大概是我功力不够吧).最近花了点时间认真看了智能指针,特地来写这篇文章. 1.智能指针是什么 简单来说,智能指针是一个类,它对普 ...

  9. C++11智能指针读书笔记;

    智能指针是一个类对象,而非一个指针对象. 原始指针:通过new建立的*指针 智能指针:通过智能指针关键字(unique_ptr, shared_ptr ,weak_ptr)建立的指针 它的一种通用实现 ...

  10. 「C++」理解智能指针

    维基百科上面对于「智能指针」是这样描述的: 智能指针(英语:Smart pointer)是一种抽象的数据类型.在程序设计中,它通常是经由类型模板(class template)来实做,借由模板(tem ...

随机推荐

  1. VJGUI消息设计-兼谈MFC、QT和信号/槽机制

    星期六下午4点,还在公司加班.终于写完了下周要交工的一个程序. 郁闷,今天这几个小时写了有上千行代码吧?虽然大部分都是Ctrl-C+Ctrl-V,但还是郁闷. 作为一个有10年经验的MFC程序员,郁闷 ...

  2. nginx配置ssl加密(单双向认证、部分https)

    nginx配置ssl加密(单双向认证.部分https) nginx下配置ssl本来是很简单的,无论是去认证中心买SSL安全证书还是自签署证书,但最近公司OA的一个需求,得以有个机会实际折腾一番.一开始 ...

  3. GitHub学习笔记

    安装 Ubuntu上安装Git sudo apt-get install git Windows上安装Git msysgit是Windows版的Git.从http://msysgit.github.i ...

  4. ShareSDK for Android 只有新浪微博分享

    本文代码例子:http://pan.baidu.com/share/link?shareid=3710053477&uk=3189484501 ShareSDK 官方的例子非常好,但代码太多看 ...

  5. Eucalyptus和Openstack最近版本的改动简单对比

    Eucalyptus3.3四月底发布的,Q4会发布3.4,最新代码都可以在Github上获得 3.3里主要加入的东西有: Auto Scaling 自动扩展,虚拟机资源随需要实时变更 ELB 负载均衡 ...

  6. Android GPS应用:临近警告

    前面介绍过LocationManager有一个addProximityAlert(double latitude,double longitude,float radius,long expirati ...

  7. css3属性——border-radius用法

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <style> ...

  8. [NOIP 2005]-- 篝火晚会

    额~~,对这组题感兴趣的具体的解题报告可以戳戳这里:http://wenku.baidu.com/view/878beb64783e0912a2162aa7.html?qq-pf-to=pcqq.c2 ...

  9. swf上传文件

    以下是自学it网--中级班上课笔记 网址:www.zixue.it 引入的js包自己在网上找一个,这里好像不支持上传文件,反正我没找到,呵呵~~ html文件 <!DOCTYPE html PU ...

  10. C#数组集合使用 排序的问题

    //没有顺序 //ArrayList a = new ArrayList(); //a.Add("asda"); //a.Add("asda222222"); ...