说起智能指针,不少人都不陌生。比方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初学者开发—第5部分:布局和事件基础

    原文 Windows Phone 8初学者开发—第5部分:布局和事件基础 原文地址: http://channel9.msdn.com/Series/Windows-Phone-8-Developme ...

  2. Shell中的正则表达式及字符串处理

    shell里一个正则表达式就是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式.该模式描述在查找文字主体时待匹配的一个或多个字符串.正则表达式作为一个模板,将某个字符模式与所 ...

  3. myeclipse设置凝视

    Window-perferences--java--Code Style--Code Templates--Commments 类凝视:Types /** *@desc *@author haozk ...

  4. QQ邮箱添加公司邮箱步骤

    经领导提示,发现QQ邮箱可以添加公司邮箱.这样,在有同事出差在外的时候,可以通过QQWEB邮箱,即可收发公司邮箱,不必安装邮箱客户端软件. 仅供各位同事参考使用. 1.打开QQ邮箱 2.点击其他邮箱, ...

  5. 面向对象程序设计-C++ Steam & Vector 【第三次上课笔记】

    大家可以下载后用Vim 或者 Sublime Text等文本编辑器查看 Conference: http://blog.csdn.net/candy1232009/article/details/70 ...

  6. 2014 HDU多校弟九场I题 不会DP也能水出来的简单DP题

    听了ZWK大大的思路,就立马1A了 思路是这样的: 算最小GPA的时候,首先每个科目分配到69分(不足的话直接输出GPA 2),然后FOR循环下来使REMAIN POINT减少,每个科目的上限加到10 ...

  7. Chapter 7 代理模式

    代理模式:为其它对象提供一种代理以控制对这个对象的访问. 代码: package xiao; class Girl{ private String name; public void setName( ...

  8. 设计模式 ( 十七) 状态模式State(对象行为型)

    设计模式 ( 十七) 状态模式State(对象行为型) 1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到.然后使用if... ...

  9. 基于visual Studio2013解决C语言竞赛题之0522和为素

     题目

  10. Eclipse3.6 添加JUnit源代码

    Eclipse中无法查看JUnit源代码,也无法设置源代码的jar. 解决方法: 1.  下载org.junit.source_4.8.1.v4_8_1_v20100427-1100.jar,放到ec ...