3

これは私のコードで一般的なパターンになりつつあります.A.「重い」またはB.クリティカルセクションなどのオペレーティングシステムリソースであるために、コピー不可にする必要があるオブジェクトを管理する必要がある場合:

class Resource;

class Implementation : public boost::noncopyable
{
    friend class Resource;
    HANDLE someData;
    Implementation(HANDLE input) : someData(input) {};
    void SomeMethodThatActsOnHandle() {
        //Do stuff
    };
public:
    ~Implementation() { FreeHandle(someData) };
};

class Resource
{
    boost::shared_ptr<Implementation> impl;
public:
    Resource(int argA) explicit {
        HANDLE handle = 
            SomeLegacyCApiThatMakesSomething(argA);
        if (handle == INVALID_HANDLE_VALUE)
            throw SomeTypeOfException();
        impl.reset(new Implementation(handle));
    };
    void SomeMethodThatActsOnTheResource() {
        impl->SomeMethodThatActsOnTheHandle();
    };
};

このようにして、shared_ptr は参照カウントの頭痛のResource種を処理し、コピー可能にすることができます。

Implementationしかし、 boost の侵入コンテナのように、何らかの方法でそのデータを内部に移動できれば、shared_ptr の参照カウントなどを個別に割り当てるオーバーヘッドを節約できそうです。

これにより、時期尚早の最適化ハックルが一部の人々を悩ませている場合、現在のプロジェクトにはこれが必要ないことに実際に同意します。しかし、それが可能かどうか興味があります。

4

4 に答える 4

6

参照カウントが埋め込まれたクラスで動作するように設計されたboost::intrusive_ptrを使用します。

ここの例に基づくテストされていない例:

class Resource; 

class Implementation : public boost::noncopyable 
{ 
    friend class Resource;
    HANDLE someData;
    int refCount; // The reference count.
    Implementation(HANDLE input) : someData(input) { refCount = 0; }; 
    void SomeMethodThatActsOnHandle() { 
        //Do stuff 
    }; 
public: 
    ~Implementation() { FreeHandle(someData) }; 
};

intrusive_ptr_add_ref(Implementation* imp) { imp->refCount++; }
intrusive_ptr_release(Implementation* imp) { if(--imp->refCount) == 0) delete imp; }

class Resource 
{ 
    boost::intrusive_ptr<Implementation> impl; 
public: 
    Resource(int argA) explicit { 
        HANDLE handle =  
            SomeLegacyCApiThatMakesSomething(argA); 
        if (handle == INVALID_HANDLE_VALUE) 
            throw SomeTypeOfException(); 
        impl.reset(new Implementation(handle)); 
    }; 
    void SomeMethodThatActsOnTheResource() { 
        impl->SomeMethodThatActsOnTheHandle(); 
    }; 
}; 
于 2010-04-02T20:38:31.890 に答える
6

部分的な解決策は、 を使用make_sharedして を作成することshared_ptrです。例えば、

auto my_thing = std::make_shared<Thing>();

それ以外の

auto my_thing = std::shared_ptr<Thing>(new Thing);

まだ邪魔にならないので、他に何も変更する必要はありません。の適切な実装はmake_shared、参照カウントとオブジェクト自体のメモリ割り当てを組み合わせたものです。これにより、メモリ割り当てが節約され、カウントがオブジェクトの近くに保持されるため、局所性が向上します。のようなものほど効率的ではありませんboost:intrusive_ptrが、検討する価値はあります。

于 2010-04-02T21:06:22.420 に答える
1

オブジェクトと参照カウンターの個別のメモリ割り当てのオーバーヘッドを削減したい場合は、make_sharedを使用してみてください。それがその目的です。

于 2010-04-02T20:44:37.810 に答える
1

2 つのクラスを取り除き、1 つだけにして共有 ptr を型定義するだけで、オーバーヘッドをいくらか節約できます。これは、私が常に使用している Idom です。

 class Resource
 {
      ...
 };
 typedef boost::shared_ptr<Resource> ResourcePtr;
于 2010-04-02T20:39:14.937 に答える