标准全局默认运算符new的对齐限制是什么?

时间:2012-10-27 04:33:17

标签: c++ visual-c++ com memory-alignment

我正在研究一些使用ATL CComBSTR类型的旧代码。我正在更改它,以便它将使用Visual C ++ Express Edition进行编译,而Visual C ++ Express Edition没有ATL。我只使用了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).- end note]

我发现这有点令人困惑 - “最弱的对齐要求”对我说“最不严格的对齐约束”,但这下的注释似乎表明标准意味着相反。

我可以安全地使用new char[sizeof(uint32_t) + 2*(length + 1)]缓冲区作为BSTR吗?

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

3 个答案:

答案 0 :(得分:5)

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

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

答案 1 :(得分: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数组,不能保证其对齐最终会是什么。

答案 2 :(得分:0)

您永远不应该尝试将C ++内存管理功能用于BSTR - 它们只应使用SysAllocString()系列函数进行分配。这可以确保获得BSTR的任何人都可以在获得的SysFreeString()上使用BSTR和其他家庭功能。如果违反此要求,您的程序将遇到未定义的行为。