1

アップデート:

ニューロンが提案したように、ベクトルのアドレスを出力してみましたが、プログラム全体で同じです。これは、重複が発生していないことを意味します。Planet と Player が定義された後、しかしプログラムが setup() と render() に到達する前に、ベクターはどういうわけか「リセット」されます。何が原因でしょうか?

更新 2:

cout を使用して、main() の前にエラーが発生していると判断しました。そのため、グローバルな Player オブジェクトと Planet オブジェクトが構築され、それらへのポインターが MasterEntityVector に追加されます。次に、main() が開始される前に (または main() が開始されたときに、その一部が実行される前に)、MasterEntityVector が「リセット」され、その後、すべてが期待どおりに実行されます。この動作は、MasterEntityVector が CircularEntity クラスの静的メンバーである場合と、MasterEntityVector が OpenGLLoopLogic.ccp でグローバルである場合の両方で発生します。この動作の原因は何ですか? 「静的初期化順序の大失敗」 http://www.parashift.com/c++-faq-lite/static-init-order.htmlと関係があるのではないかと思いますが、問題は少し異なるようです(たとえば、私はクラッシュしていません)。

更新 3:

なぜうまくいかなかったのかわかりませんが、同じ問題と解決策を持っている人を見つけました。以下の私の答えを見てください。リンクでアレックスの質問を見ると、より大きなプロジェクトは問題とは無関係であるように思われるため、プロジェクト全体を含めることを削除します (質問を元のサイズに切り詰めます)。


私の間違いが些細な場合は、事前にお詫び申し上げます。私は C++ の初心者であり、スコープと複数のファイル プロジェクトの概念を比較的よく理解していないため、何時間もかけてコードをいじったり、インターネットで答えを探したりしましたが、明らかなことを見落としている可能性があります。

以下のコードは、私の質問に答えやすくするために単純化されています。

コードブロック、C++、OpenGL (グラフィック用)、SDL (ウィンドウ用) を使用しています。

トラブルシューティングのために cout 行が追加されました。以下に出力を含めます。

問題は、MasterEntityVector と呼ばれるグローバル ベクトルです。このベクトルには、シミュレーション内のすべての「エンティティ」へのポインタが含まれているはずです。これは、CircularEntity.ccp で宣言され、CircularEntity.h で extern を使用します。ポインターは、エンティティーのコンストラクター中に追加されることになっています。OpenGLLoopLogic.ccp では、エンティティが作成されるとポインターが MasterEntityVector に追加されますが、init/setup/render 関数を開始すると、リセットされるか、作成された 2 番目のインスタンスを取得するように見えます。この望ましくない動作を止めるにはどうすればよいですか?

CircularEntity.h:

#ifndef CIRCULARENTITY_H
#define CIRCULARENTITY_H

#include "LUtil.h"

class CircularEntity {
    public:
        CircularEntity(double x, double y, int r);
        double xpos, ypos;
        int radius;
        void Draw(double camxpos, double camypos);

};

extern std::vector<CircularEntity *> MasterEntityVector;  //contains pointers to ALL entities

#endif // CIRCULARENTITY_H

CircularEntity.ccp:

#include "CircularEntity.h"

std::vector<CircularEntity *> MasterEntityVector;  //contains pointers to ALL entities

CircularEntity::CircularEntity(double x, double y, int r) {
    radius = r;
    xpos = x;
    ypos = y;
    std::cout << "test 1" << std::endl;
    std::cout << MasterEntityVector.size() << std::endl;
    MasterEntityVector.push_back(this);
    std::cout << "test 2" << std::endl;
    std::cout << MasterEntityVector.size() << std::endl;
}

...
//irrelevant code removed
...

OpenGLLoopLogic.h:

#ifndef OPENGLLOOPLOGIC_H
#define OPENGLLOOPLOGIC_H

#include "MoveableCircular.h"

//Screen constants
const int SCREEN_WIDTH = 1800;
const int SCREEN_HEIGHT = 1000;

bool initGL();
    
void setup();

void update();
    
void render();
    
void handleKeys( unsigned char key, int x, int y );

#endif // OPENGLLOOPLOGIC_H

OpenGLLoopLogic.ccp:

#include "OpenGLLoopLogic.h"

//The projection scale
GLfloat gProjectionScale = 1.f;
MoveableCircular Player(200, 200, 0, 0, .05, 10);
CircularEntity Planet(0, 0, 100);

bool initGL()
{
    ...
    //irrelevant code removed
    ...
    setup();

    return true;
}

void setup() {
    CircularEntity Planet2(0, 0, 100);
    CircularEntity Planet3(0, 0, 100);
}

void velocityupdate()
{
    Player.Gravity(0,0,100);
}

void positionupdate()
{
    Player.PositionUpdate();
}

void update()
{
        velocityupdate();
        positionupdate();
}

void render()
{
    ...
    //irrelevant code removed
    ...
    for (int n=0; n<MasterEntityVector.size(); n += 1) {
        (*MasterEntityVector[n]).Draw(Player.xpos, Player.ypos);
        std::cout << MasterEntityVector.size() << std::endl;
    }

    ...
    //irrelevant code removed
    ...
}

void handleKeys( unsigned char key, int x, int y )
{
    ...
    //irrelevant code removed
    ...
}

いくつかのファイルを省略したので、関係のないコードをたくさん読む必要はありません。

MoveableCircular のソースとヘッダーは、CircularEntity ファイルとよく似ています。(cout のテストは 1 と 2 ではなく 3 と 4 であり、MoveableCircular クラスは CirularEntity から継承され、再定義されたコンストラクターがあるだけです)。main.ccp は init を呼び出し、次にループがあります: キーを処理し、更新し、レンダリングします。「インクルード ツリー」の「上にある」MoveableCirular.h ファイル (正しい用語はわかりません) は、この問題とは何の関係もないはずです。この問題に本当に関連する唯一のことは、「#含む "

出力は次のとおりです。

test 1
0
test 2
1
test 3
1
test 4
2
test 1
2
test 2
3
test 1
0
test 2
1
test 1
1
test 2
2
2
2
2
.
.
.
[infinite 2's]

出力からわかるように、Player オブジェクトと Planet オブジェクトが構築されると、すべてがうまくいきます。ただし、OpenGLLoopLogic 関数 (セットアップでの Planet2 と Planet3、描画コードのレンダリングなど) に入ると、MasterEntityVector の 2 つ目のコピーを「リセット」または作成するように見えます。この望ましくない動作の原因は何ですか?

私がすでに試したこと:

コード全体で MasterEntityVector の前に「::」を追加

名前空間に関するもの (ただし、名前空間に関する私の知識と理解は確かに弱いため、これが問題の原因になる可能性があります)。

4

3 に答える 3

0

ほとんどのコードを読みましたが、まだいくつか質問があります。

  • あなたのコードMasterEntityVectorでは、のコンストラクターでのみ参照されCircularEntityます。それが参照されている他の場所、特にそのpop_backeraseまたは呼び出された const 以外のメソッドはありますか?
  • のオブジェクトCircularEntityとそのサブクラスは、どこで構築されましたか?
  • オーバーロードしていませCircularEntity::~CircularEntityんか?

後者の 2 つの質問に対して、バグ (?) が見つかりました。

void setup() {
    CircularEntity Planet2(0, 0, 100);
    CircularEntity Planet3(0, 0, 100);
}

CircularEntityローカルで2 つの s を構築したため、 でsetup()呼び出された後に破棄されinitGL()ます。を正しく記述した場合、から~CircularEntity削除する必要があるため、ベクトルのサイズが小さくなります。(しかし、私はの宣言を見ませんでした)thisMasterEntityVector~CircularEntity

また、グローバルベクターの別のインスタンスがあるかどうか疑問がある場合は、グローバルベクターのアドレスを出力してみてもよいと思います。

于 2013-05-27T02:54:18.143 に答える