2

正直なところ、私が経験している問題に対してタイトルが正しいかどうかはわかりません. 問題はこうです。Engine というクラスがあり、そのインスタンスが 1 つあります。

testTextureカスタムTextureクラスtestObjectのインスタンスである と、カスタム オブジェクト クラスのインスタンスであるという 2 つのメンバ変数が含まれています。

Engine 関数Initでは、これらの値は次のように設定されます。

testTexture = Texture(0, TEXT("D:\\spriteWallVertical112.png"),
                      renderer.ReturnDevice());
testObject = Object(0,testTexture.textureID, D3DXVECTOR3(0,0,0),
                    D3DXVECTOR3(100,100,100), testTexture.texture, &renderer);

これはすべて私が望むように機能しているように見えます.それらの値は保存され、うまく維持されているようです.

ただし、クラスコンストラクター内には、クラス内の次Objectの関数への呼び出しがあります。RendererAddNewTextureObject

rendererPointer->AddNewTextureObject(&objectID, &textureID, textureInput, 
                                     &origin, &coordinates);

これはうまくいくように見えますが、プログラムが値を実行すると、プログラムが進むにつれてポインターが上書きされるように見えます。それらがすぐにジャンク メモリになるわけではありませんが、ジャンク メモリであることは明らかです。必要に応じてコードを提供できますが、特に他の誰かが私が間違っていることが明らかな場合は、質問に関係のないコードでこの質問をスパムしたくありません。

TextureObjectただし、ここで最も関連性があると思うので、今のところクラスコードを投稿します。

#ifndef TEXTUREOBJECT_H
#define TEXTUREOBJECT_H
#ifndef UNICODE
#define UNICODE
#endif

#include <d3dx9.h>

class TextureObject
{
public:
    TextureObject();
    TextureObject(unsigned int *, int *, LPDIRECT3DTEXTURE9, D3DXVECTOR3 *, D3DXVECTOR3 *);
    ~TextureObject();

    unsigned int *objectID; // The object with the texture.  Use this for locating and deleting this instance of TextureObject.
    int *textureID;
    LPDIRECT3DTEXTURE9 texture; // May not be needed if we can simply select the texture via ID.
    const D3DXVECTOR3 *origin; // Needed for drawing rotations....I think.
    D3DXVECTOR3 *coordinates;
    int maintainMe;
};
#endif

変数maintainMeに割り当てた場合、変数はその値を保持します。

これはAddNewTextureObject()関数のコードです:

void Renderer::AddNewTextureObject(unsigned int *objectIDInput, int *textureIDInput, LPDIRECT3DTEXTURE9 textureInput, D3DXVECTOR3 *originInput, D3DXVECTOR3 *coordinatesInput)
{
    //testTextureObject = TextureObject(objectID, textureID, textureInput, originInput, coordinatesInput);
    testTextureObject.objectID = objectIDInput;
    testTextureObject.textureID = textureIDInput;
    testTextureObject.texture = textureInput;
    testTextureObject.origin = originInput;
    testTextureObject.coordinates = coordinatesInput;
    testTextureObject.maintainMe = 3067;

に値を代入するいずれの方法でtestTextureObjectも問題が発生することに注意してください。

これに関するご支援をいただければ幸いです。

編集:

Objectクラスのコンストラクタは次のとおりです。

Object::Object(unsigned int objectIDInput, int textureIDInput, D3DXVECTOR3 originInput, D3DXVECTOR3 coordinatesInput, LPDIRECT3DTEXTURE9 textureInput, Renderer *rendererInput)
{
    objectID = objectIDInput;
    textureID = textureIDInput;
    origin = originInput;
    coordinates = coordinatesInput;
    rendererPointer = rendererInput;
    rendererPointer->AddNewTextureObject(&objectID, &textureID, textureInput, &origin, &coordinates);
}

Object.h次のように、Objectクラスで public として宣言されます。

Object(unsigned int, int, D3DXVECTOR3, D3DXVECTOR3, LPDIRECT3DTEXTURE9, Renderer *);

EDIT2:コピーコンストラクターと代入演算子を作成しました:

Object::Object(const Object &source)
{
    objectID = source.objectID;
    textureID = source.textureID;
    texture = source.texture;
    origin = source.origin;
    coordinates = source.coordinates;
    rendererPointer = source.rendererPointer;
}

Object& Object::operator=(const Object &source)
{
    if(this == &source)
    {
        return *this;
    }

    objectID = source.objectID;
    textureID = source.textureID;
    texture = source.texture;
    origin = source.origin;
    coordinates = source.coordinates;
    rendererPointer = source.rendererPointer;

    return *this;
}

経験豊富なあなたにとって、これらは正しく見えますか? 残念ながら、これだけでは問題は解決しないようです。

4

1 に答える 1

4

デストラクタを定義し、クラスにポインタがTextureObjectあるため、3 つのルールに従う必要があります: デストラクタ、コピー コンストラクタ、および代入演算子を定義します。ポインターは から発生したObject可能性があるため、そのクラスに対しても同じことを行う必要がある場合があります。

あなたが直面している問題は、ダングリング ポインターの問題であると思います。初期化した後、初期化にtestObject使用された一時が破棄され、その中で初期化されたポインターが解放されます。したがって、testTextureObject解放されたメモリへのポインターを保持するようになりました (これらのポインターはもともと一時的なものからのものであるため)。

編集:のコンストラクターに基づいて、一時的なインスタンスである現在のインスタンスからポインターが渡されていることがObjectわかります。rendererPointer->AddNewTextureObjectObject

testObject = Object(0,testTexture.textureID, D3DXVECTOR3(0,0,0),
                    D3DXVECTOR3(100,100,100), testTexture.texture, &renderer);

このコード行は、 の一時的なインスタンスを作成Objectし、代入演算子を使用して を初期化しますtestObject。このコード行の後、テンポラリは破棄されます。現在は、存在しなくなった一時オブジェクトからのポインターに初期化された をrenderer保持しています。TextureObject

編集: 3 のルールが解決しようとしている問題について、混乱しているようです。3 の規則に関する質問に対する受け入れられた回答を読むことができます。ただし、簡単な例を示すために、メモリを割り当てるクラスの単純な問題を考えてみてください。

class Foo {
    Bar *bar;
public:
    Foo () : bar(new Bar) {}
    ~Foo () { delete bar; }
    Bar * get_bar () { return bar; }
};

デストラクタは、メモリをリークしないようにする必要があります。ただし、コピー コンストラクターまたは代入演算子を使用すると、問題が発生します。

Foo a;
Foo b(a); // copy

の問題bは、 と同じポインタを保持していることaです。したがって、baが破棄されると、ポインターは 2 回削除されます。

Foo a;
Foo c;
c = a;    // assign

問題は、 (二重削除につながる) とc同じポインターを保持しているだけでなく、コンストラクターで作成されたメモリがリークされていることです。a

ルール 3 は次のとおりです。デストラクタが必要な場合は、コピー コンストラクタと代入演算子も必要です。ルールの目的は、デストラクタを追加することによって解決する必要がある問題と、それらがコピーの構築と割り当てにどのような結果をもたらすかについて開発者に考えさせ、合理的な解決策を作成することです。

あなたの場合、一時的に作成されたrendererを保持しています。のデストラクタ、コピー コンストラクタ、および代入演算子で、または他の解決策で問題を回避することによって、状況を修正する方法を考える必要があります。TextureObjectObjectObject

于 2012-07-03T23:33:14.633 に答える