7

我正在做一个项目,其中某些对象被引用计数——这是一个与 COM 非常相似的设置。无论如何,我们的项目确实有智能指针,可以减少为这些对象显式调用 Add() 和 Release() 的需要。问题是有时,开发人员仍然使用智能指针调用 Release()。

我正在寻找的是一种从智能指针调用 Release() 创建编译时或运行时错误的方法。编译时间对我来说似乎是不可能的。我以为我有一个运行时解决方案(见下面的代码),但它也不能完全编译。显然,使用 operator->() 后不允许隐式转换。

无论如何,任何人都可以想出一种方法来完成我想要完成的事情吗?

非常感谢您的帮助!

凯文

#include <iostream>
#include <cassert>

using namespace std;

class A
{
public:
    void Add()
    {
        cout << "A::Add" << endl;
    }

    void Release()
    {
        cout << "A::Release" << endl;
    }

    void Foo()
    {
        cout << "A::Foo" << endl;
    }
};

template <class T>
class MySmartPtrHelper
{
    T* m_t;

public:

    MySmartPtrHelper(T* _t)
        : m_t(_t)
    {
        m_t->Add(); 
    }

    ~MySmartPtrHelper()
    {
        m_t->Release(); 
    }

    operator T&()
    {
        return *m_t;
    }

    void Add()
    {
        cout << "MySmartPtrHelper::Add()" << endl;
        assert(false);
    }

    void Release()
    {
        cout << "MySmartPtrHelper::Release()" << endl;
        assert(false);
    }
};

template <class T>
class MySmartPtr
{
    MySmartPtrHelper<T> m_helper;

public:

    MySmartPtr(T* _pT)
        : m_helper(_pT)
    {
    }

    MySmartPtrHelper<T>* operator->()
    {
        return &m_helper;
    }
};

int main()
{
    A a;

    MySmartPtr<A> pA(&a);

    pA->Foo(); // this currently fails to compile.  The compiler
               // complains that MySmartPtrHelper::Foo() doesn't exist.

    //pA->Release(); // this will correctly assert if uncommented.

    return 0;
}
4

4 回答 4

4

你不能这样做——一旦你重载了operator ->你就会被卡住——重载的操作符会以同样的方式表现,而不管它的右边是什么。

您可以将 Add() 和 Release() 方法声明为私有,并使智能指针成为引用计数类的朋友。

于 2009-06-05T08:08:52.570 回答
3

operator->必须返回一个本身支持的指针或对象operator->。它可以是递归的。您不能做的是operator->根据->.

我想不出任何不涉及以某种方式复制指向对象的接口的方法,或者要求您创建从指向对象公开派生的对象,并将 Add 和 Release 隐藏并在派生类中设为私有,并且使用Base* pBase = pDerived; pBase->Add();技巧从智能指针调用 add 和 release。

于 2009-06-05T08:05:49.923 回答
0

我通过更改 MySmartPtr 中的重载运算符并在 MySmartPtrHelper 中添加一个重载运算符来使其工作:

#include <iostream>
#include <cassert>

using namespace std;

class A
{
public:
    void Add()
    {
        cout << "A::Add" << endl;
    }

    void Release()
    {
        cout << "A::Release" << endl;
    }

    void Foo()
    {
        cout << "A::Foo" << endl;
    }
};

template <class T>
class MySmartPtrHelper
{
    T* m_t;

public:

    MySmartPtrHelper(T* _t)
        : m_t(_t)
    {
        m_t->Add(); 
    }

    ~MySmartPtrHelper()
    {
        m_t->Release(); 
    }

    operator T&()
    {
        return *m_t;
    }

    T* operator->()
    {
        return m_t;
    }


    void Add()
    {
        cout << "MySmartPtrHelper::Add()" << endl;
        assert(false);
    }

    void Release()
    {
        cout << "MySmartPtrHelper::Release()" << endl;
        assert(false);
    }
};

template <class T>
class MySmartPtr
{
    MySmartPtrHelper<T> m_helper;

public:

    MySmartPtr(T* _pT)
        : m_helper(_pT)
    {
    }

    T* operator->()
    {
        return m_helper.operator->();
    }
};

int main()
{
    A a;

    MySmartPtr<A> pA(&a);

    pA->Foo(); 
    //pA->Release(); // this will correctly assert if uncommented.

    return 0;
}

输出:

macbook-2:~ $ ./a.out 
A::Add
A::Foo
A::Release
于 2009-06-05T08:10:56.700 回答
0

我建议你使用类似下面的代码。除非您愿意添加一个小约束,否则您想要的东西是不可能的:对象必须是可复制构造的(并且您不介意使用这种可能性)。在这种情况下,继承是一个不错的方法。

#include <iostream>
#include <cassert>

using namespace std;

template <class T>
class MySmartPtrHelper : public T
{

public:

    MySmartPtrHelper(T* _t)
        : m_t(*_t)
    {
        delete _t;
        ((T*) this)->Add();
    }

    ~MySmartPtrHelper()
    {
        ((T*) this)->Release(); 
    }

    void Add()
    {
        cout << "MySmartPtrHelper::Add()" << endl;
        //will yield a compile-time error  
        BOOST_STATIC_ASSERT(false) 
    }

    void Release()
    {
        cout << "MySmartPtrHelper::Release()" << endl;
        //will yield a compile-time error  
        BOOST_STATIC_ASSERT(false) 
    }
};

template <class T>
class MySmartPtr
{
   MySmartPtrHelper<T>* m_helper;
   // Uncomment if you want to use boost to manage memory
   // boost::shared_ptr<MySmartPtrHelper<T> > m_helper;

public:

    MySmartPtr(T* _pT)
        : m_helper(new MySmartPtrHelper<T>(_pT))
    {
    }

    MySmartPtrHelper<T>* operator->()
    {
        return m_helper;
    }
};

int main()
{
    MySmartPtr<A> pA(new A());

    pA->Foo();

    //pA->Release(); // this will correctly assert if uncommented.

    return 0;
}
于 2009-06-05T11:26:40.707 回答