0

親愛なる皆さん、これは大変なことになりそうです: 私は希望するオブジェクトを生成するゲーム オブジェクト ファクトリを作成しました。ただし、修正できないメモリリークが発生します。

return new Object();によってメモリ リークが発生します。コードサンプルの下部にあります。

static BaseObject * CreateObjectFunc()
{
    return new Object();
}

ポインターを削除する方法と場所は? bool ReleaseClassType()を書きました。ファクトリはうまく機能しますが、ReleaseClassType() はメモリ リークを修正しません。

bool ReleaseClassTypes()
{
    unsigned int nRecordCount = vFactories.size();
    for (unsigned int nLoop = 0; nLoop < nRecordCount; nLoop++ )
    {
        // if the object exists in the container and is valid, then render it
        if( vFactories[nLoop] != NULL) 
            delete vFactories[nLoop]();
    }
    return true;
}

以下のコードを見る前に、私の CGameObjectFactory が特定のオブジェクト タイプを作成する関数へのポインタを作成することをお手伝いさせてください。ポインターは、vFactories ベクター コンテナー内に格納されます。

オブジェクト マップ ファイルを解析するため、この方法を選択しました。オブジェクト タイプ ID (整数値) を実際のオブジェクトに変換する必要があります。100 を超えるさまざまなオブジェクト データ型があるため、非常に長い Switch() ステートメントを継続的にトラバースすることは避けたいと考えました。

したがって、オブジェクトを作成するには、CGameObjectFactory::create() 経由で vFactories '['nEnumObjectTypeID']'()を呼び出して、目的のオブジェクトを生成するストアド関数を呼び出します。

vFactories 内の適切な関数の位置は nObjectTypeID と同じであるため、インデックスを使用して関数にアクセスできます。

ガベージ コレクションを続行し、報告されたメモリ リークを回避するにはどうすればよいでしょうか

#ifndef GAMEOBJECTFACTORY_H_UNIPIXELS
#define GAMEOBJECTFACTORY_H_UNIPIXELS

//#include "MemoryManager.h"
#include <vector>


template <typename BaseObject>
class CGameObjectFactory
{
public:
    // cleanup and release registered object data types
    bool ReleaseClassTypes()
    {
        unsigned int nRecordCount = vFactories.size();
        for (unsigned int nLoop = 0; nLoop < nRecordCount; nLoop++ )
        {
            // if the object exists in the container and is valid, then render it
            if( vFactories[nLoop] != NULL) 
                delete vFactories[nLoop]();
        }
        return true;
    }

    // register new object data type
    template <typename Object>
    bool RegisterClassType(unsigned int nObjectIDParam )
    {
        if(vFactories.size() < nObjectIDParam) vFactories.resize(nObjectIDParam);

        vFactories[nObjectIDParam] = &CreateObjectFunc<Object>;
        return true;
    }


    // create new object by calling the pointer to the appropriate type function
    BaseObject* create(unsigned int nObjectIDParam) const
    {
        return vFactories[nObjectIDParam]();
    }


    // resize the vector array containing pointers to function calls
    bool resize(unsigned int nSizeParam)
    {
        vFactories.resize(nSizeParam);
        return true;
    }

private:
    //DECLARE_HEAP;

    template <typename Object>
    static BaseObject * CreateObjectFunc()
    {
        return new Object();
    }


    typedef BaseObject*(*factory)();
    std::vector<factory> vFactories;
};


//DEFINE_HEAP_T(CGameObjectFactory, "Game Object Factory");

#endif // GAMEOBJECTFACTORY_H_UNIPIXELS
4

7 に答える 7

3

ガベージ コレクションを続行し、報告されたメモリ リークを回避するにはどうすればよいでしょうか。

std::shared_ptrまたはboost::shared_ptrBaseObjectを使用して、ポインターの所有権を管理することを検討してください。

于 2011-03-04T03:00:12.367 に答える
2

この行:

delete vFactories[nLoop]();

new を呼び出し、すぐにオブジェクトを削除します。ファクトリによって作成された他のオブジェクトは削除されません。リーク検出ツールは、削除されなかった割り当てのスタック トレースを提供しますか? そうでない場合は、そうするものを入手してください。

于 2011-03-04T03:07:55.160 に答える
1

他の人が言ったように、のさまざまな実装を調べてくださいshared_ptr

しかし、自分のコードが行っていると思うことを本当に実行したい場合は、 create メソッドと release メソッドを次のようにする必要があります (現在のコードはファクトリのみを格納するため、[以下で呼び出される] vectorcreated を格納するも必要になります。作成されたオブジェクトではありません):BaseObject*vObjects

public:
BaseObject* create(unsigned int nObjectIDParam)
{
    BaseObject *obj = vFactories[nObjectIDParam]();
    //I'm assuming you have error handling/detection already in code that calls this create function

    vObjects.push_back(obj);
    return obj;
}

bool ReleaseClassTypes()
{
    for (typename vector<BaseObject*>::iterator iter = vObjects.begin(); iter != vObjects.end(); ++iter) {
        if (*iter) {
            delete *iter;
            *iter = NULL; //not strictly needed, but doesn't hurt
        }
    }
    vObjects.erase();
    return true; //you might as well just convert the return type to void
}

しかし、おそらく呼び出すデストラクタをコーディングする必要がありますReleaseClassTypes

public:
~CGameObjectFactory() {
    ReleaseClassTypes();
}

そして、 3 つのルールから少し逸脱して、おそらくコピー コンストラクターと代入演算子をプライベートにして、コピーを禁止することをお勧めします (または、それらを適切に定義して新しいリソースを取得し、古いリソースを解放することもできますが、私はそうではありません)。工場をコピーする必要がある理由を確認してください)。

private:
CGameObjectFactory(const CGameObjectFactory& cgoFact) { }
CGameObjectFactory& operator=(const CGameObjectFactory& cgoFact) { return *this; }
于 2011-03-04T06:01:47.050 に答える
1

このReleaseClassTypes方法には欠陥があります:

delete vFactories[nLoop]();

基本的に言っている:

delete new Object();

を呼び出して作成したすべてのオブジェクトではなく、作成したばかりのオブジェクトを削除していますCGameObjectFactory::create()。とはいえ、作成したすべてのオブジェクトを一度にダンプできるようにするには、別のベクターが必要です。

于 2011-03-04T03:00:29.587 に答える
1

コンパイラに応じて、 std::shared_ptr または std::tr1::shared_ptr または boost::shared_ptr を使用して開始できます。

次のように使用します。

typedef std::shared_ptr<BaseObject> BaseObjectPtr;
static BaseObjectPtr CreateObjectFunc()
{
    return BaseObjectPtr(new Object());
}

作成したリソースを解放する必要はありません。それらは、自動参照カウントを行い、それを指す強い参照がない場合に自分自身を解放します。

したがって、2番目のコード例では:

#ifndef GAMEOBJECTFACTORY_H_UNIPIXELS
#define GAMEOBJECTFACTORY_H_UNIPIXELS

//#include "MemoryManager.h"
#include <vector>
#include <memory>

template <typename BaseObject>
class CGameObjectFactory
{
public:
    typedef std::shared_ptr<BaseObject> BaseObjectPtr;

    // cleanup and release registered object data types
    bool ReleaseClassTypes()
    {
        unsigned int nRecordCount = vFactories.size();
        for (unsigned int nLoop = 0; nLoop < nRecordCount; nLoop++ )
        {
            // if the object exists in the container and is valid, then render it
            //if( vFactories[nLoop] != NULL) 
            //    delete vFactories[nLoop]();
            // The above code would create something then immediately delete it.
            // You could keep a container of pointers to the objects you created
            // and loop through that instead, or use shared_ptr.
            // If you want to unregister the creator functions just NULL the pointer.
            vFactories[nLoop] = NULL;
        }
        return true;
    }

    // register new object data type
    template <typename Object>
    bool RegisterClassType(unsigned int nObjectIDParam )
    {
        if(vFactories.size() < nObjectIDParam) vFactories.resize(nObjectIDParam);

        // Store a pointer to the creation function
        vFactories[nObjectIDParam] = &CreateObjectFunc<Object>;
        return true;
    }


    // create new object by calling the pointer to the appropriate type function
    BaseObjectPtr create(unsigned int nObjectIDParam) const
    {
        return vFactories[nObjectIDParam]();
    }


    // resize the vector array containing pointers to function calls
    bool resize(unsigned int nSizeParam)
    {
        vFactories.resize(nSizeParam);
        return true;
    }

private:
    //DECLARE_HEAP;

    template <typename Object>
    static BaseObjectPtr CreateObjectFunc()
    {
        return BaseObjectPtr(new Object());
    }


    typedef BaseObjectPtr(*factory)();
    std::vector<factory> vFactories;
};


//DEFINE_HEAP_T(CGameObjectFactory, "Game Object Factory");

#endif // GAMEOBJECTFACTORY_H_UNIPIXELS

それが役立つかどうかを確認してください。

于 2011-03-04T03:01:02.317 に答える
0

提案された解決策 1: 生成されたポインターに内部ベクトルを使用する

-まだ動作していません

上記のアドバイスでは、2 つの解決策を推奨しています。最初に、別の内部ベクトルを作成して、次によって生成されたすべてのポインターを記録します

template <typename Object>
static BaseObject* CreateObjectFunc()
{   
     return new Object();
}

ベクトルは、この関数のように手動で削除する必要があります。

bool ReleaseClassTypes()
{
    unsigned int nRecordCount = vObjects.size();
    for (unsigned int nLoop = 0; nLoop < nRecordCount; nLoop++ )
    {
        if( vObjects[nLoop] != NULL) 
            delete vObjects[nLoop];
    }
    return true;
}

私はアドバイスに従ってやったし、他の多くの組み合わせも同様に疲れた. ただし、コンパイル エラーが発生します。

d:\source\satori\satori\gameobjectfactory.h(48): error C2663: 'std::vector<_Ty>::push_back' : 2 overloads have no legal conversion for 'this' pointer
1>          with
1>          [
1>              _Ty=CGameObject *
1>          ]
1>          d:\source\satori\satori\gameobjectfactory.h(45) : while compiling class template member function 'CGameObject *CGameObjectFactory<BaseObject>::create(unsigned int) const'
1>          with
1>          [
1>              BaseObject=CGameObject
1>          ]
1>          d:\source\satori\satori\resourcemanager.h(99) : see reference to class template instantiation 'CGameObjectFactory<BaseObject>' being compiled
1>          with
1>          [
1>              BaseObject=CGameObject
1>          ]

これは変更された CGameObjectFactory であり、コンパイル エラーが発生します。問題がどこにあるのかについての良いヒントを教えてください。

#ifndef GAMEOBJECTFACTORY_H_UNIPIXELS
#define GAMEOBJECTFACTORY_H_UNIPIXELS

#include "GameObject.h"
#include <vector>


template <typename BaseObject>
class CGameObjectFactory
{
public:
    //typedef std::shared_ptr<BaseObject> BaseObjectPtr;
    // cleanup and release registered object data types
    bool ReleaseClassTypes()
    {
        //unsigned int nRecordCount = vFactories.size();
        unsigned int nRecordCount = vObjects.size();
        for (unsigned int nLoop = 0; nLoop < nRecordCount; nLoop++ )
        {
            if( vObjects[nLoop] != NULL) 
                delete vObjects[nLoop];
        }
        return true;
    }


    // register new object data type
    template <typename Object>
    bool RegisterClassType(unsigned int nObjectIDParam )
    {
        if(vFactories.size() < nObjectIDParam) vFactories.resize(nObjectIDParam);
        vFactories[nObjectIDParam] = &CreateObjectFunc<Object>;

        return true;
    }


    // create new object by calling the pointer to the appropriate type function
    BaseObject* create(unsigned int nObjectIDParam) const
    {
        BaseObject* pObject = vFactories[nObjectIDParam]();
        vObjects.push_back(pObject);
        return pObject;
    }


    // resize the vector array containing pointers to function calls
    bool resize(unsigned int nSizeParam)
    {
        vFactories.resize(nSizeParam);
        return true;
    }

private:
    //DECLARE_HEAP;

    template <typename Object>
    static BaseObject* CreateObjectFunc()
    {   
        return new Object();
    }



    typedef  BaseObject* (*factory)();
    std::vector<factory> vFactories;
    std::vector<BaseObject*> vObjects;

};


//DEFINE_HEAP_T(CGameObjectFactory, "Game Object Factory");

#endif // GAMEOBJECTFACTORY_H_UNIPIXELS
于 2011-03-04T17:00:20.107 に答える
0

提案された解決策 2: スマート ポインターの使用

-まだ動作していません

上記のアドバイスでは、2 つの解決策を推奨しています。2 番目の解決策では、スマート ポインターを使用することをお勧めします。以下のコードが示すように、キー ポインターを std::smart_ptr に置き換えました。

#ifndef GAMEOBJECTFACTORY_H_UNIPIXELS
#define GAMEOBJECTFACTORY_H_UNIPIXELS

#include "GameObject.h"
#include <vector>
#include <memory>


template <typename BaseObject>
class CGameObjectFactory
{
public:
    typedef std::shared_ptr<BaseObject> BaseObjectPtr;

    // cleanup and release registered object data types
    bool ReleaseClassTypes()
    {
        unsigned int nRecordCount = vFactories.size();
        for (unsigned int nLoop = 0; nLoop < nRecordCount; nLoop++ )
        {
            // if the object exists in the container, then delete it
            if( vFactories[nLoop] != NULL) vFactories[nLoop] = NULL;
        }
        return true;
    }


    // register new object data type
    template <typename Object>
    bool RegisterClassType(unsigned int nObjectIDParam )
    {
        if(vFactories.size() < nObjectIDParam) vFactories.resize(nObjectIDParam);
        vFactories[nObjectIDParam] = &CreateObjectFunc<Object>;

        return true;
    }


    // create new object by calling the pointer to the appropriate type function
    BaseObjectPtr create(unsigned int nObjectIDParam) const
    {
        return vFactories[nObjectIDParam]();        
    }


    // resize the vector array containing pointers to function calls
    bool resize(unsigned int nSizeParam)
    {
        vFactories.resize(nSizeParam);
        return true;
    }

private:
    //DECLARE_HEAP;

    template <typename Object>
    static BaseObjectPtr CreateObjectFunc()
    {   
        return BaseObjectPtr(new Object());
    }



    typedef  BaseObjectPtr(*factory)();
    std::vector<factory> vFactories;

};


//DEFINE_HEAP_T(CGameObjectFactory, "Game Object Factory");

#endif // GAMEOBJECTFACTORY_H_UNIPIXELS

コードは正常にコンパイルされます。ただし、次のエラーが表示されます。

デバッグ エラー!

ヒープ破損が検出されました: 0x04DC7E68 での通常のブロック (#949) の後。

CRT は、アプリケーションがヒープ バッファーの終了後にメモリに書き込んだことを検出しました。

割り当てられたメモリ: CGameObjectFactory の行へのファイルパス: return BaseObjectPtr(new Object());*

ポップアップウィンドウには、AbortRetryIgnoreの 3 つのオプションがあります。

Ignoreを繰り返し押すと、割り当てられたゲーム ポインターのベクター コンテナーが明らかに削除されます。一方、Abortを押すと、メモリリークが再び発生します。

それは何を示しているのでしょうか?私は自分のコードで特別なことをしていないので、この動作を完全に理解していないと思います。

于 2011-03-04T18:51:46.970 に答える