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);
}

编辑:谁格式化了我的代码,谢谢。我对这里的格式不太好,现在看起来好多了:)

进一步编辑:我已经验证了 fooMatrix 的初始化在我调用 std::cout后正在运行。

UPTEENTH 编辑:这是初始化 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次编辑:这不仅仅是输出问题。我实际上必须在其他地方使用矩阵的值,它的值与所描述的行为一致(无论我是否打印它)。

树第三次编辑:通过调试器运行它又给了我一个不同的价值:

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

a(g 64 , g 64 )th 编辑:在 linux 上编译不存在问题。仅在带有 MinGW 的 Windows 上。会不会是编译器错误?那会让我很难过。

最终编辑:它现在可以工作了。我不知道我做了什么,但它有效。我已经确定我使用的是最新版本,它没有确保因果关系仍然有效的代码,并且它可以工作。感谢您帮助我解决这个问题,stackoverflow 社区。和往常一样,你一直乐于助人,容忍我的迟钝。我将对任何可能导致这种不可预测性的未定义行为或指针错误保持高度警惕。

4

2 回答 2

3

您不是在逐条编写程序指令。您正在向 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 回答