内存那些事之野指针

       在稍大点的软件工程中,我们经常需要用到基于接口的回调在达到模块解耦/通信的目的.甚至在超大的工程中,类似这样的回调机制比如委托(Delegate)会成为系统重要的基础部件,为分模块的系统开发提供良好的底层支持.

       但是随着这样的机制被大量使用,指针的生命周期管理,循环重入等问题导致野指针的问题就越来越突出,极大的破坏了软件的稳定性,造成业务的损失.本文重点探讨提供一种机制,把这种情况下野指针的危险降到最低.

       首先我们看一种典型的应用场景.socket模块通常需要通知外部模块一些信息,比如收包,连错错误/成功之类的.一般会有如下调用;

       pISocket->setSocketSink(pSocketSink);

       这里设置了回调后,如果指针的生命周期管理失当,就会形成野指针而宕机.实际应用中可能情况更复杂.比如典型的 mmorpg中,模块能达到几十个.他们的交互(更多的是基于委托)会更加频繁和复杂,出问题的可能性会大很多.

       为了能够让所有有保存指针的模块能感知到指针的失效,需要把回调指针再包一层.这个额外的中间层,主要包含以下三个参数:

template<class clsSink>

class SafeHandle

{

clsSink* m_pSink;

//回调指针.

int* m_refCount;

//引用计数,控制所有引用同一个指针的句柄相关动态申请变量的生存周期

bool* m_isValid;

//一旦无效,可以让所有引用该指针的句柄都无效..

}

再让回调接口继承以下接口:

template<class clsSink>

class ISafeSink

{

public:

typedef SafeHandle<clsSink> SinkSafeCls;

private:

SinkSafeCls m_safeHandle;

public:

ISafeSink()

{

m_safeHandle.setNewSink(static_cast<clsSink*>(this));

}

~ISafeSink(){ m_safeHandle.setValid(false);}

const SinkSafeCls& getSafehandle() { return m_safeHandle;}

};

对于回调指针而言,如下继承即可:

class ISimple   : public ISafeSink<ISimple>

{

};

        这里虽然解决了野指针问题,但是对于安全回调和非安全的,使用这套东西的人却需要不同的编码.即 前者保存的是SafeHandle<clsSink>,后者直接保存回调指针.为了保持一致性,让外部使用者不用关心回调的实现细节.我们需要做更深一层的封装.

          我们首先需要做的根据回调接口是否有继承自ISafeSink,定义/获取不同的类型。再把

SafeHandle操作符重载.让SafeHandle<clsSink>跟单独的回调指针具有相同的外部调用逻辑.其中 判断是否有继承关系的类大概如下:

template<class Base,class Derived>

class IsDerived

{

struct char2 { char c[2];};

static Derived& makeDerived();

static char test(...);

static char2 test(const Base&);

typedef  SaveType<sizeof(test(makeDerived()))==sizeof(char) ? 1 : 0,  Derived>   HelperType;

};

我们使用这个回调实现的话,如下调用即可

class testClass

{

SavePtrThis<ISimple>::PtrType m_safeSink;

public:

void addSink(ISimple * p)

{

m_safeSink =  SavePtrThis<ISimple>::FuncType::get_ptr(p);

}

void run()

{

if(!m_safeSink)

{

printf("句柄非法..\n");

return;

}

m_safeSink->testFunc();

}

 };

 

 最后附上单元测试的代码,在VC9及gcc 4.4编译通过

  http://kevincodelib.googlecode.com/files/SafeSink.zip

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值