m = XMMatrixIdentity() - 类中的对齐内存后崩溃

Crash after m = XMMatrixIdentity() - alignment memory in classes?

本文关键字:对齐 内存 崩溃 XMMatrixIdentity      更新时间:2023-10-16

我正在查看DirectX SDK中的教程。教程 5 工作正常,但是在我将代码复制并分离到我自己的类后,我在启动应用程序时遇到了奇怪的错误。

该行是:

g_World1 = XMMatrixIdentity();

因此,我在运算符=中遇到了错误 xnamathmatrix.int 看起来像这样:

XMFINLINE _XMMATRIX& _XMMATRIX::operator=
(
    CONST _XMMATRIX& M
)
{
    r[0] = M.r[0];
    r[1] = M.r[1];
    r[2] = M.r[2];
    r[3] = M.r[3];
    return *this;
}

错误消息是:

Access violation reading location 0xffffffff

我在某处读到它可能是由与XMFLOAT4X4/XMmatrix相关的内容引起的:

您是否考虑过使用 XMFLOAT4X4 来存储矩阵,并且只使用 XMMATRIX?

但我想我已经使用了XMMATRIX。

MyClass.h:

private:
    XMMATRIX g_World1;

我的类.cpp:

void init(){
   g_World1 = XMMatrixIdentity();
}

我认为我不应该将 XMMATRIX g_World1; 更改为 XMFLOAT4X4 g_World1,因为它会产生以下错误:

错误 C2679:二进制"=":未找到采用类型为"XMMATRIX"的右侧操作数的运算符(或者没有可接受的转换)

由于 XMMATRIX 表示一个 16 字节对齐的 4x4 矩阵,因此未对齐的g_World1分配会导致访问冲突(简单地说,g_World1 的地址不能被 16 整除)。

解决方案:使结构成员对齐 16 个字节(让 MyClass 具有"就位"g_World1)。但是,您仍然必须确保MyClass实例驻留在可被16整除的地址上。

您可以使用放置"new"运算符来分配 MyClass 对象。

关于对齐方式,请参见此处:如何对齐指针

XMVECTOR和XMMATRIX是"寄存器代理"类型。您可以安全地将它们用作 Xbox 360、Xbox One 和 Windows x64 平台的类型,因为它们在堆栈上的数据本机都具有 16 字节对齐方式,并在堆上分配。

将它们用于Windows 32位或Windows RT/ARM需要花费更多的精力,因为本机对齐方式超过16字节。一种方法是 DirectX 工具包使用的技术...它使用 pImpl 惯用法,并且 pImpl 内部类显式分配了 16 字节对齐方式,这是直接使用 XMVECTOR 和 XMMATRIX 类型的地方。另一种方法是使用所有各种"存储"类型,如XMFLOAT4和XMFLOAT4X4。

注意:DirectXMath程序员指南涵盖了这一点。这不是一个很长的文档,它包含了很多提示和建议。

PS:MSDN Code Gallery上有一个版本的Win32桌面标准Direct3D教程,不需要DirectX SDK...它只使用VS 2012或VS 2013附带的Windows 8.x SDK。

谢谢。

最后,我决定使用 XMLoadFloat4x4() 和 XMStoreFloat4x4() 函数。我将类的成员存储为 Float4x4,并将它们临时转换为 XMMATRIX 每个 render() 循环。但。。。这是一个快速还是愚蠢的解决方案?

在"Frank D. Luna"的"Introduction to 3D Game Programming with Directx 11"一书中说:

不要将 XMMATRIX 用作类或结构的成员。始终使用 XMFloat4x4 并在需要时加载和存储。