Scoped Reference Idiom的最佳实践?

Fur*_*der 2 c++ pointers

我被一个错误所困,部分原因在于我缺乏理解,部分原因是我认为我们的代码库中设计欠次优.我很好奇我的5分钟解决方案是如何改进的.

我们使用的是ref-counting对象,我们在这些类的对象上有AddRef()和Release().一个特定的对象是从ref-count对象派生的,但是获取这些对象的实例(GetExisting)的常用函数会在其自身内部隐藏AddRef()而不会通知它正在这样做.这需要在功能块的末尾执行Release以释放隐藏的ref,但是没有检查GetExisting()的实现的开发人员不会知道这一点,并且忘记在最后添加Release的人这个函数(比如说,在一个疯狂的bug修复关键时刻)泄漏了对象.当然,这是我的烧伤.


void SomeFunction(ProgramStateInfo *P)
{
   ThreadClass *thread = ThreadClass::GetExisting( P );
   // some code goes here
   bool result = UseThreadSomehow(thread);
   // some code goes here
   thread->Release();  // Need to do this because GetExisting() calls AddRef()
}
Run Code Online (Sandbox Code Playgroud)

所以我编写了一个小类来避免在这些函数结束时需要Release().


class ThreadContainer
{
private:
    ThreadClass *m_T;
public:
    ThreadContainer(Thread *T){ m_T = T; }
    ~ThreadContainer() { if(m_T) m_T->Release(); }
    ThreadClass * Thread() const { return m_T; }
};
Run Code Online (Sandbox Code Playgroud)

所以现在我可以这样做:


void SomeFunction(ProgramStateInfo *P)
{
   ThreadContainer ThreadC(ThreadClass::GetExisting( P ));
   // some code goes here
   bool result = UseThreadSomehow(ThreadC.Thread());
   // some code goes here
   // Automagic Release() in ThreadC Destructor!!!
}
Run Code Online (Sandbox Code Playgroud)

我不喜欢的是,要访问线程指针,我必须调用ThreadContainer的成员函数Thread().有没有一些聪明的方法可以清理它,以便它在语法上更漂亮,或者是否会使容器的含义模糊不清并为不熟悉代码的开发人员引入新问题?

谢谢.

bay*_*yda 10

使用boost :: shared_ptr可以定义自己的析构函数,如下例所示:http://www.boost.org/doc/libs/1_38_0/libs/smart_ptr/sp_techniques.html#com


mwi*_*ahl 7

是的,您可以operator ->()为类实现,它将以递归方式调用operator ->()您返回的内容:

class ThreadContainer
{
private:
    ThreadClass *m_T;
public:
    ThreadContainer(Thread *T){ m_T = T; }
    ~ThreadContainer() { if(m_T) m_T->Release(); }
    ThreadClass * operator -> () const { return m_T; }
};
Run Code Online (Sandbox Code Playgroud)

它有效地为你的包装类使用智能指针语义:

Thread *t =  new Thread();
...
ThreadContainer tc(t);
...
tc->SomeThreadFunction(); // invokes tc->t->SomeThreadFunction() behind the scenes...
Run Code Online (Sandbox Code Playgroud)

您还可以编写转换函数以UseThreadSomehow(ThreadContainer tc)类似方式启用类型调用.

如果Boost是一个选项,我认为你也可以设置一个shared_ptr作为智能参考.