代码之家  ›  专栏  ›  技术社区  ›  Kevin

智能指针是否可以选择性地隐藏或重新引导函数调用到它们要包装的对象?

  •  7
  • Kevin  · 技术社区  · 17 年前

    我正在做一个项目,在这个项目中,某些对象被引用计数——这是一个非常类似于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 回复  |  直到 17 年前
        1
  •  4
  •   sharptooth    17 年前

    你不能这样做-一旦你超载了 operator -> 你被卡住了-超载的操作员在没有它右边的情况下也会以同样的方式工作。

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

        2
  •  3
  •   CB Bailey    17 年前

    operator-> 必须返回指针或自身支持的对象 运算符-GT; . 它可以是递归的。你不能做的就是 运算符-GT; 根据出现在 -> .

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

        3
  •  0
  •   Lodle    17 年前

    我通过更改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
    
        4
  •  0
  •   Benoît photo_tom    17 年前

    我建议您使用如下代码。 你想要的是不可能的 除非 您愿意添加一个小约束:对象必须是可复制构造的(您不介意使用这种可能性)。在这种情况下,继承是一种很好的方式。

    #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;
    }