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 に答える