说起智能指针,不少人都不陌生。比方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. Windows Phone 8初学者开发—第3部分:编写第一个Windows Phone 8应用程序

    原文 Windows Phone 8初学者开发—第3部分:编写第一个Windows Phone 8应用程序 原文地址: http://channel9.msdn.com/Series/Windows- ...

  2. maven安装jar到本地仓库

    class12.jar这个东西在中央仓库里没有,所以,cmd到oracle\product\10.2.0\db_1\jdbc\lib路径下,mvn install 就好了(发布第三方jar到本地库) ...

  3. 安卓开发37:自定义的HorizontalScrollView类,使其pageScroll的时候焦点不选中

    自定义一个HorizontalScrollView类,主要为了让这个HorizontalScrollView不能鼠标点击,不能左右按键,并且没有焦点. public class ImageMoveHo ...

  4. android 获取本机号码需要root吗?

    首先要明白,有的手机是获取不到自身的手机号的, 查了些资料,有以下两种方式可以获取到:      1. 通过对方给你发短信,打电话获取本机号码:       2. 还有一个就是通过APN来查询,但是这 ...

  5. Sicily-1024

    一. 题意: 有n个节点,n-1条边,并且任意两个节点都连通.模拟一下,实际上是一棵树的便利,求从特定根节点出发最长路径的值.这里用了广搜. 二. 每个节点只有两条邻接边,每个节点用一个vector来 ...

  6. ligh@local-host$ ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.0.3

    ligh@local-host$ ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.0.3

  7. org.tigris.subversion.javahl.ClientException: Attempted to lock an already-locked dir svn: Working c

    Eclipse插入svn提交出现:org.tigris.subversion.javahl.ClientException: Attempted to lock an already-locked d ...

  8. source code of MES Data

    <HTML> <HEAD> <TITLE>TELOGS</TITLE> </HEAD> <BODY> <?php /* c ...

  9. 打印NSLog分类 Foundation+Log.m

    #import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @implementation UIView(Log) + ...

  10. QuartusII中调用Modelsim的方法

    Modelsim的使用 1,  建立工程编译通过之后——证明实例工程无语法等简单错误.编写testbench 2,  将testbench 添加到工程中,进行编译通过.会在工程的file中看到test ...