1

C ++で参照のリストまたはマップを作成し、それらが破棄されるとその要素を自動的に削除したいと思います。これがそのアイデアを示す構造です。

class Foo;

class Bar
{
    Foo foo;
};

void main(void)
{
    std::vector<Foo> foos;

    {
        Bar bar;
        foos.push_back(bar.foo);

        // foos[0] should be the same reference as bar.foo
    }

    // bar is now destructed
    // foos.size() should be 0
}

私のコードには2つの問題があります。std :: vectorで呼び出されるとpush_back()、Fooオブジェクトのコピーが作成されます。foosの要素はで行われた変更を反映する必要があるため、これは受け入れられませんbar.foo。次に、foosベクターが参照を格納できたとしても、作成されたスコープを離れた後、Fooオブジェクトはリストから削除されませんbar。理想的には、Foo参照がfoos破棄されたときに削除されるようにしたいと思います。

独自のソリューションを実装する前に、これを提供するサードパーティのライブラリ(Boost、おそらく?)、またはこれに使用する必要のある適切な手法や戦略について知りたいと思います。ありがとう!

4

3 に答える 3

5

最良のオプションは、弱ポインタ​​ーのコンテナーを使用することだと思います。(コンパイラが何らかの理由でC ++ 11またはTR1をサポートしていない場合は、Boostで使用できます。)

弱いポインタは、ターゲットが破棄されると、適切に初期化されていると仮定すると、自動的に無効になります。

弱いポインタのコンテナ内のすべての有効なポインタを取得するためのサンプルコードを次に示します。

template <class T>
std::vector<std::shared_ptr<T> > MassLock(const std::vector<std::weak_ptr<T> >& weakptrs)
{
    std::vector<std::shared_ptr<T> > sharedptrs;

    for(unsigned int i=0; i<weakptrs.size(); ++i)
    {
        if (std::shared_ptr<T> temp = weakptrs.at(i).lock())
        {
            sharedptrs.push_back(temp);
        }
    }

    return sharedptrs;
}

そして、これがすべての無効なポインタを一掃する方法です。

template <class T>
struct isInvalid : public std::unary_function<T, bool>
{
    bool operator() (T rhs) { return !rhs.lock(); }
};

template <class T>
void EraseInvalid( std::vector<T>& targetlist )
{
    targetlist.erase( remove_if(targetlist.begin(), targetlist.end(), isInvalid<T>() ), targetlist.end());
}
于 2012-08-05T03:03:03.903 に答える
1

同じオブジェクトへの複数の参照が必要な場合は、std::shared_ptr(またはC ++ 11がない場合はBoostからの)のような「スマート」ポインターのコンテナーが必要になる可能性があります。

于 2012-08-05T03:05:18.273 に答える
0

(Antimonyによって提案されたように)weak_ptrを使用して参照を保持するようにリストを変更し、次のように破壊された要素の削除を自動化します。

まず、いくつかの言い回しを明確にしましょう。要素を削除すると実際に要素が破壊されるため、タイトルは「破棄されると要素への参照を自動的に削除するC ++コンテナ」である必要があります。したがって、破棄時に「削除」されるのではなく、それへの参照をコンテナから削除したい。

std::list<std::weak_ptr<Foo>> foos;

{
    // create a new entry in the container
    const auto& iter = foos.insert(foos.end(), std::weak_ptr<Foo>());
    // create an object of type "Foo" and store it in a shared_ptr
    std::shared_ptr<Foo> foo
        (new Foo
        // set a custom deleter that actually deletes the object
        // AND erases it from the container
        , [&foos, iter](Foo* ptr)
            {
                delete ptr;
                foos.erase(iter);
            }
        );
    // set the pointer to the element into the container
    *iter = foo;
}

// the shared_ptr "foo" ran out of scope;
// as there is no further strong reference to its object
// , the custom deleter was called which has removed the entry from the container
// so foos.size() is now 0

コンテナをベクトルからリストに変更したことに注意してください。これは、ベクトルがイテレータを無効にする可能性があるため(カスタム削除機能に渡されます。ベクトルのサイズ変更はイテレータを無効にしますか?を参照)、リストは無効にしません。ベクトルに固執したい場合は、カスタムデリータに渡される要素への参照としてインデックスを使用できますが、end()の前に要素をベクトルに挿入すると、この参照が破損することに注意してください。

于 2017-01-11T16:33:48.557 に答える