C++智能指针的实现
说起智能指针,不少人都不陌生。比方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++智能指针的实现的更多相关文章
- enote笔记法使用范例(2)——指针(1)智能指针
要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...
- C++11 shared_ptr 智能指针 的使用,避免内存泄露
多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...
- C++智能指针
引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...
- EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针
一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...
- 智能指针shared_ptr的用法
为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...
- 智能指针unique_ptr的用法
unique_ptr是独占型的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,如下面错误用法: std::unique_pt ...
- 基于C/S架构的3D对战网络游戏C++框架_05搭建系统开发环境与Boost智能指针、内存池初步了解
本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...
- C++ 引用计数技术及智能指针的简单实现
一直以来都对智能指针一知半解,看C++Primer中也讲的不够清晰明白(大概是我功力不够吧).最近花了点时间认真看了智能指针,特地来写这篇文章. 1.智能指针是什么 简单来说,智能指针是一个类,它对普 ...
- C++11智能指针读书笔记;
智能指针是一个类对象,而非一个指针对象. 原始指针:通过new建立的*指针 智能指针:通过智能指针关键字(unique_ptr, shared_ptr ,weak_ptr)建立的指针 它的一种通用实现 ...
- 「C++」理解智能指针
维基百科上面对于「智能指针」是这样描述的: 智能指针(英语:Smart pointer)是一种抽象的数据类型.在程序设计中,它通常是经由类型模板(class template)来实做,借由模板(tem ...
随机推荐
- Swift - 1 (常量、变量、字符串、数组、字典、元组、循环、枚举、函数)
Swift 中导入类库使用import,不再使用<>,导入自定义不再使用"" import Foundation 1> 声明变量和常量 在Swift中使用 &qu ...
- C# RSA在服务上使用出现拒绝方法错误的解决方法
在做一个快钱接口的时候,遇到了.net RSA加密无法在一台win2008服务器上运行正常,更换到Win2003服务器后出现问题,具体表现如下: “/”应用程序中的服务器错误. ----------- ...
- LNK 2005 error 函数定义也是定义!!
url=Ccne-rWwUO9tJp5YAPcycUw09__2whgZLpLw2aWVuYuE-fhu46kaVNX4BldWlsxig1tDML47aO_ctD3PcUlGjK"> ...
- MyEclipse10+Jdk1.7+OSGI+MySql实现CRUD数据库
开发环境: Windows2008R2 64位置+MyEclipse10+jdk1.7.0_67+MySql5.5 软件安装:myeclipse-10.0-offline-installer-wind ...
- 【转载】Java重构示例【1】
序言 本文通过Java示例代码片段展示了常用重构原则和技巧,供初级开发人员参考.精致的代码能够清楚传达作者的意图,精致的代码是最好的注释,精致的代码非常容易维护和扩展.程序员阅读精致的代码如同大众欣赏 ...
- [Swust OJ 191]--迷宫逃离(打表搜索)
题目链接:http://acm.swust.edu.cn/problem/191/ Time limit(ms): 1000 Memory limit(kb): 65535 江鸟突然想到了一个 ...
- C# 网络编程 Part.1
本人也是新手,对网络编程一窍不通,所以从今天开始我将学习网络编程的基础知识,在此一一贴出来,编辑成一个系列! 1.为自己复习巩固用 2.可以找到同时在学习网络编程的同学,一起讨论交流,促进学习效率及其 ...
- php四舍五入函数(floor、ceil、round与intval)
原文链接:php四舍五入函数(floor.ceil.round与intval) PHP(外文名: Hypertext Preprocessor,中文名:“超文本预处理器”)是一种通用开源脚本语言.语法 ...
- 观django-messages包笔记
django_messages是一个提供注册用户之间互相发送消息的django app.最近在研究其实现机制,安装测试非常容易,导入包,配好url以及syncdb生成数据库即可使用. 一.收获一: 我 ...
- linux 学习:环境变量设置
一.临时环境变量 临时环境变量,只对当前打开的shell生效,shell关闭后,环境变量失效. 设置方法一: 分两步 MYPARA=hello export MYPARA 设置方法二:一步完成 exp ...