1

ゲーム エンジンで読み込まれた同じテクスチャの重複を避けるために、コンテンツ管理システムを作成しています。以下は、以前にロードされたオブジェクトからコンテンツを取得するための関数、または使用可能なオブジェクトがない場合に新しいオブジェクトをロードするための関数です。

    template <class T>
    T* GetContent(const char* path) {
        // Check if it already exists, if yes return it
        for (ContentEntry& entry : m_ContentList) {
            // Same Type?
            if (strcmp(entry.Type, T::GetType()) == 0)
                // Same Path?
                if (strcmp(entry.C->GetPath(), path) == 0)
                    return (T*)entry.C;
        }

        // Since it doesn't exist, create it
        ContentEntry contentEntry (
            T::GetType(),
            (Content*)new T(path));

        // Add it to the list
        m_ContentList.push_back(contentEntry);

        // And Return it
        return (T*)contentEntry.C;
    }

これは、コンテンツ エントリとそれらが格納されているベクトルを格納するために使用される構造体です。

    struct ContentEntry {
        const char* Type;
        Content* C;

        ContentEntry(const char* type, Content* c) :
            Type(type),
            C(c)
        { }
        ~ContentEntry() {
            delete C;
        }
    };

    std::vector<ContentEntry> m_ContentList;

この関数が値を返そうとするたびに、アプリがクラッシュします。contentEntry をポインターに変更すると (その周りのコードを適切に更新すると)、問題なく返されますが、ベクター全体を変更して ContentEntry ポインターを指すようにし、可能であれば回避したいものを手動で削除する必要があります。この機能を正しく動作させるにはどうすればよいですか?

さらに、ポインタを使用して foreach ループをステップ実行すると、明確な理由もなくベクトルが大幅に増加するように見えます。これを防ぐにはどうすればよいですか?

編集:今のところクラッシュの問題は修正されていますが、後で調整しますが、制御不能なベクトルはまだそこにあります。

Edit2:関数を終了した後、成長するベクトルが消えているように見えるので、何かを回答としてマークします。

4

3 に答える 3

2

見た目から、文字列のように見えるものをdeleteではなくを使用して削除していますdelete[]。もちろん、これは文字列が最初に割り当てられたことを前提としています。あなたのコメントに基づいて、deleteその時点で未定義の動作を引き起こす文字列リテラルを試みます。

そうは言っても、オブジェクトをベクターに挿入するときにオブジェクトをスライスしていることに注意してください。さらに重要なことに、ContentEntryメンバーのディープ コピーを取得しないことに注意してください (この型にはコピー コンストラクターがなく、おそらく代入演算子もありません)。したがって、を挿入した後ContentEntrystd::vector<ContentEntry>新しく割り当てられたオブジェクトはなくなります。もう 1 つの興味深い点は、 を にキャストすることT*ですContent*。割り当てオブジェクトはdelete、へのポインタを介して dContentです。したがって、キャストが不要である (そしてうまくいけば、型Contentvirtualデストラクタがある) か、その時点で事態が悪化し始めます。

于 2013-08-14T23:49:22.033 に答える
1
    // Since it doesn't exist, create it
    ContentEntry contentEntry (
        T::GetType(),
        (Content*)new T(path));

    // Add it to the list
    m_ContentList.push_back(contentEntry);

    // And Return it
    return (T*)contentEntry.C;

問題はContentEntry、コピー コンストラクター (およびコピーの割り当て) がないことと組み合わせて、これらの 3 行にあります。

  • 最初の部分で ContentEntry インスタンスを作成します
  • 次にpush_back、そのインスタンスのコピーを取得します。このコピーは、オリジナルContentEntryが指していたのと同じ T インスタンスを指します。
  • 最後に、関数は終了し、T へのポインタを返します。しかし、終了時にローカル コピーcontentEntryが破棄されdelete、返されたポインターが指す T インスタンスが破棄されます。

本質的に、あなたは3 つのルールに従っておらず、罰を受けています。

于 2013-08-15T00:03:55.817 に答える
0

ContentEntry のコピー コンストラクターが必要です。

于 2013-08-15T00:19:24.963 に答える