分享
 
 
 

一个智能指针的实现(改进)

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

一个智能指针的实现(改进)

单承亮 (Simouse) 2004-8-22

前些日子写了一个shared_ptr,后来在应用中发现了些安全漏洞,这篇文档是对shared_ptr改进后的使用和注意事项的一个简要说明,希望广大C++开发者给予意见和改进。让我们在复杂的系统中杜绝内存泄漏。这次改进并没有增加什么功能,而是删除了几个存在安全问题的操作,如release操作。有关和STL里的auto_ptr之间的转换我也做了一些测试,目前只提供auto_ptr到shared_ptr的单向转换,因为auto_ptr只有一个拥有权,所以我们无法确定最终是由谁释放内存。我还是希望从头对这个类做一个新的说明,希望是对以前疏忽的一个弥补。

Template class shared_data

shared_data是管理指针并计数的类,是多个shared_ptr对象共同管理的一个私有对象,多个shared_ptr对象以共有同一个shared_data对象来实现管理指针的计数与释放。

class shared_data

{

friend class shared_ptr<T>;

private:

explicit shared_data(T* pT) ;

~shared_data() ;

void plus(); // 计数加1

void minus(); // 计数减2

T* get(); // 返回T类型指针

const T* get() const ; // 为了处理const对象

private:

T* _M_ptr; // 管理的T类型指针

unsigned int _M_nCount; // 计数器

};

shared_ptr是shared_data友员类,所以只有shared_ptr对象才能访问shared_data对象,把shared_data的内容写成private还是有好处的,比以前写那个shared_data还是精简了些。

成员说明:

T* _M_ptr;

这是我们分配出来的对象T的指针,也是我们管理的对象。

unsigned int _M_nCount;

这是我们的计数变量,初始时是1,构造新对象时加1,析构时减1,

当为0时又minus释放资源,包括被管理的T对象和共有的shared_data 对象。

T* get();和const T* get() const;是为了兼容const对象

Template class shared_ptr

shared_ptr是用来操作shared_data对象并提供给我们操作T对象接口,所有同类型的shared_ptr可以有多可实例,但只有一个所共享的管理类shared_data,当shared_ptr对象做Copy或Assignment操作时会对当前管理的(如果有的话)shared_data对像做minus操作,实现计数减1 ,关于是否释放的问题由minus决定;然后得到新的shared_data对象并对它做plus操作,实现计数加1。

class shared_ptr

{

typedef shared_data<T> element;

public:

explicit shared_ptr(T* pT);

explicit shared_ptr();

shared_ptr(const shared_ptr<T>& rT);

~shared_ptr();

const shared_ptr<T>& operator = (const shared_ptr<T>& rT) ;

T& operator* ();

const T& operator* () const;

T* operator-> ();

const T* operator-> () const ;

bool operator== (const shared_ptr<T>& rT) const;

bool operator== (const T* pT) const;

bool operator!= (const T* pT) const ;

T* get() ;

const T* get() const;

void reset(T* pT);

private:

element* get_element() const;

element* _M_pD;

};

数据区

成员_M_pD,是shared_data对象的指针,是多个shared_ptr实例共同管理的对象, shared_ptr只负责shared_data的分配,不负责释放,其它操作就是对shared_data计数做plus和minus操作,内存的释放又minus操作激发。

公用成员函数

构造函数加一explicit是为了避免有如这样的操作:shared_ptr<Ctest> ptrT = &t;在默认构造里我们不分配shared_data对象。当传进来NULL我们也不分配shared_data对象。值得一说的是做Assignment操作时一定要对现有的shared_data对象做minus操作。析构只对shared_data做minus操作。

Operator ->, *, ==和get都提供了两个版本,主要是兼容const对象,有一个共同点就是都是通过shard_data的get获得T对象的指针。

如果要重置shared_ptr的话reset是唯一的方法,我们可以传个NULL进去来置空shared_ptr对象,也可以重新分配新的管理对象,也可以从现有的shared_ptr对象重置,不过这有点像Assignment操作。

注:关于删除release操作是为了管理对象释放的唯一性,shared_ptr与auto_ptr接口基本相同,但由于shared_ptr是允许多个实例,最终释放都是不确定的,所以我们应尽量避免自己释放资源,一切由shared_ptr来管理。

Test

我们先定义一个简单的测试类

class CTest

{

public:

CTest(char* lpszName){

m_lpszName = lpszName;

cout<<"CTest() : " <<m_lpszName <<endl;

}

void Set(char* lpszName){

m_lpszName = lpszName;

}

~CTest(){

cout<<"~CTest() : " <<m_lpszName <<endl;

}

void Print() const{

cout<< "Print() : " <<m_lpszName <<endl;

}

private:

char* m_lpszName;

};

下面我们着重看下测试问题:

void main()

{

// Test constructor

// 这是我们标准定义shared_ptr对象的方法

shared_ptr<CTest> t1(new CTest("t1"));

// Test copy constructor

// 当然有现成的这样最好

shared_ptr<CTest> t2(t1);

// Test assignment operator

shared_ptr<CTest> t3 = t1;

// 在做->和*操作前最好判断下shared_ptr对象是不为NULL

if (t3 != NULL){ // 记住不能是if (NULL != t3),因为没有写这个操作

// 也不用怕写成if(t3 = NULL),因为也没写这个操作(:

// do some operator

}

// Test operator->

cout <<"\nTest operator->" <<endl;

cout <<"t1->Print()\t";

t1->Print();

cout <<"t2->Print()\t";

t2->Print();

cout <<"t3->Print()\t";

t3->Print();

// Test operator*

cout <<"\nTest operator*" <<endl;

cout <<"(*t1).Print()\t";

(*t1).Print();

cout <<"(*t2).Print()\t";

(*t2).Print();

cout <<"(*t3).Print()\t";

(*t3).Print();

// Test get

// 当你要用T对象指针时也可以把它取出来,不过不要做delete,要考虑shared_ptr的

// 有效期

cout <<"\nTest get\t" <<endl;

cout <<"t1.get()->Print()\t";

t1.get()->Print();

// Test operator==

cout <<"\nTest operator==" <<endl;

cout <<"t1 == t2\t" <<(t1 == t2) <<endl;

cout <<"t1 == t2.get()\t" <<(t1 == t2.get()) <<endl;

// Test reset

cout <<"\nTest reset" <<endl;

// reset 和 assignment最大的区别是它能分配新的对象

cout <<"t2.reset(new CTest(\"t2\"))\t" <<endl;

t2.reset(new CTest("t2"));

cout <<"t3.reset(new CTest(\"t3\"))\t" <<endl;

t3.reset(t2);

// Test const type

// 这些操作都是不允许的,那我们也阻止这种事儿的发生

const shared_ptr<CTest> t4(new CTest("t4"));

t4.get()->Print();

//t4->Set("Hello"); // Error

//(*t4).Set("Hello"); // Error

//t4 = t3; // Error

//t4.release(); // Error

//t4.reset(NULL); // Error

// Test compatible for auto_ptr

// 值得一提的是我们可以很轻松的从auto_ptr转到shared_ptr,不过不是往返而是单向

// 为什么?你想让auto_ptr和shared_ptr同时释放同一块内存吗?如果你只有一个

// shared_ptr拥有这块内存是可以的,你能保证吗?这就是为什么我写shared_ptr的目的。

auto_ptr<CTest> t5(new CTest("t5"));

shared_ptr<CTest> t6;

t6.reset(t5.release());

t6->Print();

if (NULL == t5.get()){

cout <<"t5 = NULL" <<endl;

}

// are you sure do it?

t5.reset(t6.get());

// 这时你知道是auto_ptr释放CTest还是shared_ptr释放?所以不要这么做!

cout <<"\nTest End!\n" <<endl;

}

由于水平有限,可能有的地方存在问题,欢迎大家加于改善,在此给出全部代码,供大家参考

File: shared_ptr.h

//////////////////////////////////////////////////////////////////////////

//

// Module Name :

//

// Template class shared_ptr

//

// Author:

//

// Chengliang Shan 2004-08-22

//

// simouse@126.com

//

//////////////////////////////////////////////////////////////////////////

#ifndef SHARED_PTR_H_

#define SHARED_PTR_H_

namespace clshan {

template<class T>

class shared_ptr;

template<class T>

class shared_data

{

friend class shared_ptr<T>;

private:

explicit shared_data(T* pT):_M_ptr(NULL), _M_nCount(0) {

if (NULL != pT) {

_M_ptr = pT;

_M_nCount = 1;

}

}

~shared_data() {

}

void plus() {

++_M_nCount;

}

void minus() {

--_M_nCount;

if (0 == _M_nCount) {

delete _M_ptr;

delete this;

}

}

T* get() {

return _M_ptr;

}

const T* get() const {

return _M_ptr;

}

private:

T* _M_ptr;

unsigned int _M_nCount;

};

template<class T>

class shared_ptr

{

typedef shared_data<T> element;

public:

explicit shared_ptr(T* pT):_M_pD(NULL) {

if (NULL != pT) {

_M_pD = new element(pT);

}

}

explicit shared_ptr():_M_pD(NULL){

}

// copy constructor

shared_ptr(const shared_ptr<T>& rT) {

_M_pD = rT.get_element();

if (NULL != _M_pD) {

_M_pD->plus();

}

}

~shared_ptr() {

if (NULL != _M_pD) {

_M_pD->minus();

}

}

// assignment operator

const shared_ptr<T>& operator = (const shared_ptr<T>& rT) {

if (NULL != _M_pD) {

_M_pD->minus();

}

_M_pD = rT.get_element();

if (NULL != _M_pD) {

_M_pD->plus();

}

return *this;

}

T& operator* () {

return *_M_pD->get();

}

const T& operator* () const {

return *_M_pD->get();

}

T* operator-> () {

return _M_pD->get();

}

const T* operator-> () const {

return _M_pD->get();

}

bool operator== (const shared_ptr<T>& rT) const {

if (NULL != _M_pD) {

return _M_pD->get() == rT.get();

}

return NULL == rT.get();

}

bool operator== (const T* pT) const {

if (NULL != _M_pD) {

return _M_pD->get() == pT;

}

return NULL == pT;

}

bool operator!= (const T* pT) const {

if (NULL != _M_pD) {

return _M_pD->get() != pT;

}

return NULL != pT;

}

T* get() {

if (NULL != _M_pD) {

return _M_pD->get();

}

return NULL;

}

const T* get() const {

if (NULL != _M_pD) {

return _M_pD->get();

}

return NULL;

}

void reset(T* pT) {

if (NULL != _M_pD) {

_M_pD->minus();

_M_pD = NULL;

}

if (NULL != pT) {

_M_pD = new element(pT);

}

}

void reset(const shared_ptr<T>& rT) {

if (NULL != _M_pD) {

_M_pD->minus();

_M_pD = NULL;

}

if (NULL != rT.get()) {

_M_pD = rT.get_element();

_M_pD->plus();

}

}

private:

element* get_element() const {

return _M_pD;

}

element* _M_pD;

};

}

#endif

http://simouse.51.net/shared_ptr.doc

http://simouse.51.net/soft/shared_ptr.h

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有