0

時間的に逆方向に移動するクラスをコーディングしたようです。説明させてください:

OrthogonalCamera::project()行列を特定の値に設定する関数、があります。次に、そのマトリックスの値をそのまま出力します。

cam.project();

std::cout << "My Projection Matrix: " << std::endl << ProjectionMatrix::getMatrix() << std::endl;

cam.project()行列をProjectionMatrixのスタックにプッシュし(私はstd :: stackコンテナを使用しています)、ProjectionMatrix::getMatrix()スタックの最上位の要素を返します。このコードだけを実行すると、次の出力が得られます。

 2      0      0      0      
 0      7.7957 0      0      
 0      0      -0.001 0      
-1     -1      -0.998 1   

しかし、呼び出し後にこれらの行でコードを実行するとstd::cout

float *foo = new float[16];

Mat4 fooMatrix = foo;

次に、この出力を取得します。

 2      0      0      0      
 0     -2      0      0      
 0      0      -0.001 0      
-1      1      -0.998 1    

私の質問は次のとおりです。値を出力した後に実行されるコードが、出力される値を変更するように、何ができるでしょうか。

私が使用している関数のいくつか:

static void load(Mat4 &set)
{
    if(ProjectionMatrix::matrices.size() > 0)
        ProjectionMatrix::matrices.pop();

    ProjectionMatrix::matrices.push(set);
}
static Mat4 &getMatrix()
{
    return ProjectionMatrix::matrices.top();
}

void OrthogonalCamera::project()
{
    Mat4 orthProjection = { { 2.0f / (this->r - this->l), 0, 0, -1 * ((this->r + this->l) / (this->r - this->l)) },
    { 0, 2.0f / (this->t - this->b), 0, -1 * ((this->t + this->b) / (this->t - this->b)) },
    { 0, 0, -2.0f / (this->farClip - this->nearClip), -1 * ((this->farClip + this->nearClip) / (this->farClip - this->nearClip)) },
    { 0, 0, 0, 1 } }; //this is apparently the projection matrix for an orthographic projection. 

    orthProjection = orthProjection.transpose();

    ProjectionMatrix::load(orthProjection);
}

編集:私のコードをフォーマットした人は誰でも、ありがとう。私はここでのフォーマットがあまり得意ではありません、そしてそれは今ではずっと良く見えます:)

さらに編集: std :: coutを呼び出した後、fooMatrixの初期化が実行されていることを確認しました。

UPTEENTH EDIT:fooMatrixを初期化する関数は次のとおりです。

typedef Matrix<float, 4, 4> Mat4;

template<typename T, unsigned int rows, unsigned int cols>
Matrix<T, rows, cols>::Matrix(T *set)
{
    this->matrixData = new T*[rows];

    for (unsigned int i = 0; i < rows; i++)
    {
        this->matrixData[i] = new T[cols];
    }

    unsigned int counter = 0; //because I was too lazy to use set[(i * cols) + j]

    for (unsigned int i = 0; i < rows; i++)
    {
        for (unsigned int j = 0; j < cols; j++)
        {
            this->matrixData[i][j] = set[counter];
            counter++;
        }
    }
}

g 64番目の編集:これは単なる出力の問題ではありません。私は実際に他の場所でマトリックスの値を使用する必要があり、その値は説明されている動作(印刷するかどうかに関係なく)と一致します。

TREE 3rd EDIT:デバッガーで実行すると、さらに異なる値 が得られました。

-7.559 0      0      0      
0      -2     0      0      
0      0      -0.001 0      
1      1      -0.998 1    

a(g 64、g 64)番目の編集:Linuxでのコンパイルに問題はありません。MinGWを搭載したWindows上で。コンパイラのバグでしょうか?それは私を悲しくさせるでしょう。

最終編集:これで動作します。何をしたかわかりませんが、機能します。因果関係が機能することを保証するコードがない最新のビルドを使用していることを確認しました。これは機能します。私がこれを理解するのを手伝ってくれてありがとう、stackoverflowコミュニティ。いつものように、あなたは私の遅さに対して助けになり、寛容でした。この予測不可能性を引き起こす可能性のある未定義の動作やポインタの混乱については、過覚醒します。

4

2 に答える 2

3

あなたは命令ごとにあなたのプログラム命令を書いているのではありません。その動作をC++コンパイラに記述し、C++コンパイラは同じことをマシンコードで表現しようとします。

コンパイラは、観察可能な動作が変わらない限り、コードを並べ替えることができます。

言い換えれば、コンパイラはほぼ確実にコードを並べ替えています。では、なぜ観察可能な行動が変化するのでしょうか?

コードが未定義の動作を示すためです。

繰り返しますが、あなたはC++コードを書いています。C ++は標準であり、コードの「意味」が何であるかを示す仕様です。あなたは「プログラマーである私がC++標準に従って解釈できるコードを書く限り、コンパイラーであるあなたは私のソースコードと同じ振る舞いをする実行可能ファイルを生成する」という契約の下で働いています。

コードがこの標準で指定されていないことを行っている場合は、この契約に違反していますC++標準に従って動作を解釈できないコンパイラコードをフィードしました。そして、すべての賭けはオフになります。コンパイラはあなたを信頼しました。それはあなたが契約を履行すると信じていました。コードを分析し、明確に定義された意味を持つコードを作成するという前提に基づいて実行可能ファイルを生成しました。そうしなかったので、コンパイラは誤った仮定の下で動作していました。そして、その仮定に基づいて構築されたものもすべて無効です。

ガベージイン、ガベージアウト。:)

残念ながら、エラーを特定する簡単な方法はありません。コードの一部を注意深く調べるか、デバッガーで問題のあるコードをステップスルーしてみることができます。または、「間違った」値が表示された時点でデバッガーに侵入し、逆アセンブルとその到達方法を調べます。

それは苦痛ですが、それはあなたにとって未定義の振る舞いです。:)静的分析ツール(Linux上のValgrind、およびVisual Studioのバージョンによっては、/analyzeスイッチが使用できる場合とできない場合があります。Clangには同様のオプションが組み込まれています)が役立つ場合があります

于 2012-05-30T22:40:13.337 に答える
2

あなたのコンパイラは何ですか?gccでコンパイルしている場合は、徹底的で詳細な警告をオンにしてみてください。Visual Studioを使用している場合は、警告を/ W4に設定し、すべての警告をエラーとして扱います。

それを実行してコンパイルできるようになったら、バグがまだ存在する場合は、Valgrindを介してプログラムを実行します。プログラムのある時点で、以前の時点で、配列の終わりを超えて読み取り、何かを書き込んでいる可能性があります。あなたが書いたものは、あなたが印刷しようとしているものを上書きしています。したがって、スタックにさらに多くのものを置くと、ある配列の終わりを超えて読み取ると、メモリ内のまったく異なる場所に配置されるため、代わりに別のものを上書きすることになります。Valgrindはそのようなものを捕まえるために作られました。

于 2012-05-30T22:36:53.493 に答える