6

A*に引数として渡したいヒープが割り当てられているとしましょうboost::bindboost::bindのコンテナーのような STL で後で処理するために保存されboost::functionsます。

A*STLコンテナの破棄時に確実に破棄されるようにしたい。

説明するには:

A* pA = new A();

// some time later
container.push_back(boost::bind(&SomeClass::HandleA, this, pA);

// some time later
container is destroyed => pA is destroyed too

どうすればそれができますか?

編集

多分私が望んでいることはそれほど現実的ではありません。

私は生のポインタと生のポインタを受け取る関数を持っています。呼び出しはboost::bindによって遅延されます。この時点で、boost::bind を実行したい場合に備えて、自動メモリ管理が必要です。私は怠け者なので、「準備完了」のスマート ポインター ソリューションを使用したいと考えています。

std::auto_ptrは良い候補のように見えますが...

auto_ptr<A> pAutoA(pA);
container.push_back(boost::bind(&SomeClass::HandleA, this, pAutoA);

コンパイルされません (こちらを参照)

auto_ptr<A> pAutoA(pA);
container.push_back(boost::bind(&SomeClass::HandleA, this, boost::ref(pAutoA));

pAutoA が破棄され、基になる pA が削除されます。

編集 02

上記のコンテナーでは、さまざまな引数を使用してさまざまな「コールバック」を保存する必要があります。それらのいくつかは、オブジェクトへの生のポインターです。コードが古いので、いつでも変更できるとは限りません。

コールバックをコンテナーに格納するための独自のラッパーを作成することは最後の手段です (おそらく唯一の手段ですが)。

4

4 に答える 4

3

私はあなたがいくつかの関数を持っていることを意味していると思います.それを呼び出すとしましょf()う. 代わりにBoost/TR1 を受け入れるようにこの機能を変更できますか? (または、可能性は低いですが C++98 ) を使用すると、ライフサイクルの問題が解決するはずです。A*boost::bindshared_ptr<A>shared_ptrstd::auto_ptr

または、それ自体を変更できない場合は、を受け入れ、生のポインターを引き出して呼び出すfラッパーを作成できます。これらのラッパーを大量に作成していることに気付いた場合は、関数のシグネチャが似ていると仮定して、それらを生成するためのテンプレートを作成できる場合があります。shared_ptr<A>f

于 2011-05-11T12:19:39.663 に答える
1

非常に複雑である必要はありません。

class MyContainer : public std::vector<boost::function<void ()> > {
public:
   void push_back(boost::function<void ()> f, A *pA) 
       { push_back(f); vec.push_back(pA); }
   ~MyContainer() 
       { int s=vec.size; for(int i=0;i<s;i++) delete vec[i]; }
private:
   std::vector<A*> vec;
};

std :: vector参照の代わりにMyContainer&を介して他の関数に渡す必要があるという1つの問題があります。そうしないと、元のpush_backを呼び出すことができ、A*ポインターを指定せずにpush_backできる場合があります。また、バインドパラメータがpAと同じA*オブジェクトであるかどうかのチェックもありません。push_backプロトタイプを変更することで、これを修正できます。

template<class T>
void push_back(T *object, void (T::*fptr)(), A *pA) 
{
   push_back(boost::bind(fptr, object, pA)); vec.push_back(pA);
} 
于 2011-05-15T18:21:55.723 に答える
1

注意!これは醜いです!

いくつかの概念実証をスクラッチしたところです。まあ、私が見る限り、それは要求したことを行いますが、これは const_cast の仮定に依存しています。プログラムでそのようなものを使用することにした場合は、プログラムで発生するすべてのコピー構造を常に再確認し、valgrind を使用して何もリーク/破損していないことを確認する準備をしてください。

トリックは、const 修飾子を無視し、auto_ptr を参照する const からの auto_ptr 所有権の転送を許可する独自のラッパー クラスを定義することです。たとえば、ベクトル自体をコピーしようとすると、これはおかしなことになる可能性があります。

そのため、ベクター コピーのセマンティクス、auto_ptr 所有権の譲渡のセマンティクスについて注意して読んでください。何よりも、shared_ptr を使用してください :)

#include <iostream>
#include <boost/bind.hpp>
#include <algorithm>
#include <vector>
#include <boost/function.hpp>

class parameter_data
{
    public:
    ~parameter_data()
    {
        std::cout << "~parameter_data()" << std::endl;
    }

    parameter_data()
    {
        std::cout << "parameter_data()" << std::endl;
    }
};

void f( parameter_data* data )
{
    std::cout << "Processing data..." << std::endl;
};


class storage_wrapper
{
    private:
        boost::function<void()> callable;
        std::auto_ptr<parameter_data> data;
    public:
        storage_wrapper( const storage_wrapper& copy ) 
        {
            callable = const_cast< storage_wrapper&>(copy).callable;
            data = const_cast< storage_wrapper&>(copy).data;
        }

        storage_wrapper( parameter_data *adata )
            : data( adata )
        {
            callable = boost::bind( &f, adata );
        }

        storage_wrapper& operator=( const storage_wrapper& copy)
        {
            callable = const_cast< storage_wrapper&>(copy).callable;
            data = const_cast< storage_wrapper&>(copy).data;
        }

        void operator()()
        {
            callable();
        }
};

int main()
{
    std::cout << "Start of program" << std::endl;
    {
        std::vector<storage_wrapper> container;
        for ( int i = 0; i < 100; i++ )
            container.push_back( storage_wrapper( new parameter_data() ) );
        for ( int i = 0; i < 100; i++ )
            container[i]();
    }
    std::cout << "End of program" << std::endl;
    return 0;
}
于 2011-05-11T15:34:06.043 に答える