为什么 glm::mat3 和 glm::value_ptr 创造了一个穿越时间和宇宙的黑洞,并正在摧毁我脑海中任何可能的逻辑?

Why does glm::mat3 and glm::value_ptr creates a black hole through time and universe and is destroying any possible logic in my mind?

我正在使用著名的 OpenGL 框架创建一个漂亮的图形引擎,但后来出现了一个意想不到的问题(就像所有问题一样)。

我必须创建一个函数来修改 glm::mat3 中的特定值。为此,我创建了一个简单的函数,return 我是对 glm::mat3 中特定浮点数的简单引用,但似乎没有任何效果,我不知道是什么原因。

这是我的函数:

float& mat3ValueAt(glm::mat3& m, int l, int c) {
    // l is the line index and c is the column index...
    return glm::value_ptr(m)[3 * l + c];
}

为了查看它是否有效,我必须使用能够显示我的矩阵的函数:

std::ostream& operator<<(std::ostream& stream, glm::mat3 m) {
    for (int i = 0; i < 9; i++) {
        stream << GLS::mat3ValueAt(m, i / 3, i % 3) << ((i + 1) % 3 ? ' ' : '\n');
    }
    return stream;
}

所有这些都不起作用...但是没关系...一定是我的问题...所以我将我看起来不错的无效代码减少到我能找到的最小代码异常...

这就是我最终完全生气并让我发疯的原因:

int main() {
    glm::mat3 m;
    std::cout << "display uninitialised value..." << std::endl;
    std::cout << *(glm::value_ptr(m) + 5) << std::endl; // should display an uninitialised value
    *(glm::value_ptr(m) + 5) = 42;
    std::cout << "display the initialised value" << std::endl;
    std::cout << *(glm::value_ptr(m) + 5) << std::endl; // should display 42
}

这段小代码的结果是...

display uninitialised value...
42
display the initialised value
42

所以我之前的两个函数不起作用这一事实是可以的,也许我只是不知道 value_ptr 是如何工作的......但我很确定一件事...... 一个值不能有我们要分配给它之前分配给它的值!

我输入的值而不是 42 并不重要,它总是在我赋值之前赋值!

这怎么可能?

这个:

glm::mat3 m;

创建一个未初始化的对象;此对象的内容具有不确定的值。任何尝试读取具有不确定值的对象的值都会导致未定义的行为。

因此,编译器可以随意 re-order 您的代码看起来像这样:

int main() {
    glm::mat3 m;
    *(glm::value_ptr(m) + 5) = 42;
    std::cout << "display uninitialised value..." << std::endl;
    std::cout << *(glm::value_ptr(m) + 5) << std::endl; // should display an uninitialised value
    std::cout << "display the initialised value" << std::endl;
    std::cout << *(glm::value_ptr(m) + 5) << std::endl; // should display 42
}

这是完全有效的,因为如果您在初始化之前尝试读取该值,您将处于未定义行为领域,并且已经初始化该值并不比任何其他未定义行为更正确。