0

私のアプリケーションでは、次のような派生クラスから動的に割り当てられたオブジェクトで満たされた配列を作成して返しています。

void someGetter(std:vector<DerivedClass> & returnV)
{
    BaseClass* base = object->clone();  // "object" is a "unique_ptr<BaseClass>"

    DerivedClass* derived = dynamic_cast<DerivedClass*> (base);

    if (derived != nullptr)
    {
        returnV.push_back(*derived);
    }
    else
    {
        delete base;
    }
}

派生は削除されないため、これは明らかにメモリ リークを引き起こします (ここでは valgrinds が役立ちます)。

次のように割り当てられたメモリを解放しようとしました:

delete &returnV[0];

コンパイル エラーや警告は発生せず、コードは正常に動作します。しかし、valgrind はそのコード行でいくつかの追加エラー (無効な読み取り、無効な解放) を報告し、リークはまだ残っています。

このように返されたメモリを解放する方法はありますか? または、オブジェクトの代わりに unique_ptr を返す必要がありますか?

4

4 に答える 4

6

タイプのを保持するベクトルを作成する場合Derived、メモリ リークを除いてコードは正しいです。解放する必要があるオブジェクトは、コンテナー内のオブジェクト (コピー) ではなく、複製したオブジェクトであることに注意してください。

void someGetter(std:vector<DerivedClass>&  returnV)
{
    BaseClass* base = object->clone(); (object is a unique_ptr<BaseClass>)
    DerivedClass* derived = dynamic_cast<DerivedClass> (base);
    if (derived != nullptr)
    {
        returnV.push_back(*derived);
    }
    delete base;
}

さらに、clone()それが言うことを行う場合(つまり、オブジェクトを複製する場合)、最初dynamic_castbaseオブジェクトDerivedClass. その場合は、コピーをコンテナーに挿入し、複製を回避します。

于 2012-09-26T12:35:24.137 に答える
3

簡単な答え-常にベースを削除します。

if (derived != nullptr)
{
    returnV.push_back(*derived);
}
delete base;

ベクターは派生のコピーを取ります-したがって、クローンオブジェクトはもう必要ありません。

[アップデート]

仮想デストラクタが含まれていることを願っていますBaseClass-そうでない場合は-それを追加します。

そしてもう1つの警告:base->clone()派生したものよりも派生したものを返すことが起こる可能性があります:

class MoreDerivedClass : public DerivedClass {};

次に、ベースの実際のクラスが次の場合でも、このコードは成功しますMoreDerivedClass

DerivedClass* derived = dynamic_cast<DerivedClass> (base);

あなたtypeid()はベースの実際のタイプをチェックするために使用することができます...


[UPDATE2]
デザインを少し変更することを検討してください。そして、ベースのクローンをDerivedClassのunique_ptrのベクトルに保持します。

void someGetter(std:vector<std::unique_ptr<DerivedClass>> & returnV)
{
    if (dynamic_cast<DerivedClass*>(base.get()) != nullptr)
    {
        returnV.push_back(dynamic_cast<DerivedClass*>(base->clone()));
    }
}
于 2012-09-26T12:37:21.267 に答える
2

まず、デザインは私には非常に疑わしいようです。一度にポリモーフィックな階層があり、その階層の特定のメンバーのを保持するコンテナーもあります。あなたが招いている問題に終わりはありません。を持っている方がはるかに賢明なようです。std::vector<std::unique_ptr<Base>>

とにかく、動的タイプが正確に一致するオブジェクトのみをコンテナに挿入するための適度に安全で効率的な方法があります。階層内のすべてのクラスにアクセス可能なコピーコンストラクターがあることを前提としています。

void someGetter(std:vector<DerivedClass> & returnV)
{
    if (typeid(*object) != typeid(DerivedClass)) { return; }

    returnV.insert(static_cast<DerivedClass&>(*object));
}

これのセマンティクスは、あなたのコードとは少し異なります。これは、コードが、*objectよりも厳密に派生型である場合を許可DerivedClassし、ベクトルにコピーするとオブジェクトがスライスされるためです。現在のコードはこの問題に悩まされていません。


更新(コメントの後):もしそうならDerivedClassfinalそしてそれをそのようにマークしてください!)、以下はなしで行いますtypeid

void someGetter(std:vector<DerivedClass> & returnV)
{
    if (DerivedClass * p = dynamic_cast<DerivedClass *>(object.get()))
    {
        assert(typeid(*p) == typeid(DerivedClass));   // beware of slicing!

        returnV.insert(*p);
    }
}
于 2012-09-26T12:58:28.807 に答える
1

はい、push_backコピー コンストラクターを使用します。デビッドはあなたのコードは

void someGetter(std:vector<DerivedClass>&  returnV)
{
    DerivedClass*derived = dynamic_cast<DerivedClass*>(object.get());
    if (derived != nullptr)
        returnV.push_back(*derived);
}

クローン作成と削除を完全に回避します。

編集で追加されたメモ:から取得したポインタを、コピーを保持する可能性のある関数に渡してはならず、unique_ptr<>.get()の要点全体に逆らいunique_ptrます。上記のコードはそれを行いません。

于 2012-09-26T12:51:14.390 に答える