7

我正在处理一些使用 ATLCComBSTR类型的旧代码。我正在更改它,以便它可以使用 ATL 不附带的 Visual C++ Express Edition 进行编译。我只使用了一个非常小的子集CComBSTR,所以这样做相当简单。

但是,在分配BSTR内存块时,我需要用 4 字节长度的前缀填充前四个字节。我担心如果我使用new char[size]表达式为字符串分配内存,由于分配的char数组没有正确对齐四字节前缀,我会导致对齐错误。

标准中是否有任何内容说明返回值new具有哪些对齐要求?我在 C++11 中看到的是:

5.3.4/1 [expr.new]
是否支持过度对齐类型由实现定义(3.11)。

3.11/6 [basic.align]
完整类型的对齐要求可以使用 alignof 表达式(5.3.6)查询。此外,char、signed char 和 unsigned char 类型应具有最弱的对齐要求。[注意:这使字符类型能够用作对齐内存区域(7.6.2)的基础类型。-结束注释]

我觉得这有点令人困惑——“最弱的对齐要求”对我来说是“对对齐的最严格限制”,但下面的注释似乎表明标准的意思是相反的。

我像这样使用new char[sizeof(uint32_t) + 2*(length + 1)]缓冲区安全吗?BSTR

编辑:我刚刚意识到,在这种特定情况下BSTR,无论如何都需要使用 SysAllocString 来分配字符串;new但我仍然对以这种方式使用是否可以感兴趣。

4

3 回答 3

7

这是一个实现细节,但 MSVC 使用操作系统分配器。HeapAlloc() 用于 CRT 分配,CoTaskMemAlloc() 用于 COM 类型包装器,如 _bstr_t。在 32 位和 64 位代码中,它们都以 8 对齐。

您永远不应该使用new运算符为 BSTR 分配内存,必须使用 COM 分配器来确保使用正确的堆释放它们。在使用 BSTR 的任何互操作场景中都很重要,它是标准的自动化类型。CoTaskMemAlloc/Free() 是必需的,但始终使用 BSTR 辅助函数来确保它们被正确初始化。SysAllocString() 和 SysFreeString()。使用 SysAllocStringLen() 处理包含嵌入零的字符串。

于 2012-10-27T16:21:35.077 回答
4

5.3.4/1 [expr.new]

是否支持过度对齐的类型是实现定义的(3.11)。

这里有一件重要的事情:over-aligned意味着比任何内置类型都更加对齐。例如,在 64 位机器上,指针通常是 8 字节对齐的,因此在那些机器上过度对齐意味着对齐严格大于 8。

因此,over-aligned仅在使用向量类型时才需要关注,例如 SSE 或 AVX 指令或 C/C++ 的某些变体(如 Open CL)所需的那些。在日常编程中,您从内置类型中创建的类型永远不会过度对齐。

§3.11 对齐 [basic.align]

3/扩展对齐由大于 的对齐表示alignof(std::max_align_t)。是否支持任何扩展对齐以及支持它们的上下文是实现定义的(7.6.2)。具有扩展对齐要求的类型是过度对齐类型。

9/如果实现不支持在特定上下文中进行特定扩展对齐的请求,则程序格式错误。此外,对于动态存储的运行时分配请求,其所请求的对齐不能被兑现,应被视为分配失败。

此外,习惯new上返回与 对齐的内存alignof(std::max_align_t)。这是因为正::operator new则只知道要分配的对象的大小,而不知道它的对齐方式,因此需要满足程序中可能的最强对齐要求。

另一方面,当心char在堆栈上分配的数组,不能保证它的对齐方式最终会是什么。

于 2012-10-27T14:05:24.003 回答
0

你永远不应该尝试对 BSTR 使用 C++ 内存管理函数——它们应该只使用SysAllocString()族函数分配。这保证了谁获得了就获得了BSTR可以使用SysFreeString()家庭的其他功能BSTR。如果您违反此要求,您的程序将遇到未定义的行为。

于 2012-10-29T12:30:28.370 回答