如何强制对齐堆分配的对象?

时间:2014-02-20 01:34:35

标签: c++ c++11 memory-alignment

How use alignof to force alignment for a heap allocation?中,我询问如何将alignof用于堆分配的对象。现在我正在概括我的问题任何方式来强制对齐堆分配的对象,因为我找不到使用alignofstd::aligned_storage的方法,或std::align。下面的代码编译,但VC12和Clang 3.2都没有产生零序列作为输出,表明我的对齐请求正在被尊重。 (gcc 4.8.1缺少std::align,但如果你对该部分进行注释,代码将在gcc 4.8.1下编译,并产生输出,表明我的对齐请求被忽略。)

#include <iostream>
#include <memory>

int main()
{
  // Try using alignas on the allocation
  {
    class Widget {};

    for (int i = 0; i < 5; ++i)
      {
        auto ptr = new alignas(64) Widget;
        std::cout << (long)ptr % 64 << '\n';    // should be 0
      }
  }

  // Try using alignas on the type
  {
    class alignas(64) Widget {};

    for (int i = 0; i < 5; ++i)
      {
        auto ptr = new Widget;
        std::cout << (long)ptr % 64 << '\n';    // should be 0
      }
  }

  // Try using std::aligned_storage
  {
    class Widget {};

    using WidgetStorage_t = 
      std::aligned_storage<sizeof(Widget), 64>::type;

    for (int i = 0; i < 5; ++i)
      {
        auto ptr = new WidgetStorage_t;         // get buffer
        new (ptr) Widget;                       // construct Widget
        std::cout << (long)ptr % 64 << '\n';    // should be 0
      }
  }

  // Try using operator new + std::align
  {
    class Widget {};

    for (int i = 0; i < 5; ++i)
      {
        auto requestSize =      // double space to ensure that a
          2 * sizeof(Widget);   // Widget fits after ptr adjustment

        auto ptr = operator new(requestSize);   // get buffer

        std::align(64, sizeof(Widget),          // align ptr 
                   ptr, requestSize);           // inside buffer

        new (ptr) Widget;                       // construct Widget

        std::cout << (long)ptr % 64 << '\n';    // should be 0
      }
  }
}

更新:我上面的测试代码std::align不正确。以下替换代码有效:

 // Try using operator new + std::align
  {
    class Widget {};

    for (int i = 0; i < 5; ++i)
      {
        auto requestSize =       // ensure that a
          sizeof(Widget) + 64;   // Widget fits after ptr adjustment

        auto ptr = operator new(requestSize);   // get buffer

        std::align(64, sizeof(Widget),          // align ptr 
                   ptr, requestSize);           // inside buffer

        new (ptr) Widget;                       // construct Widget

        std::cout << (long)ptr % 64 << '\n';    // should be 0
      }
  }

这是完成工作的唯一方法吗?它比我想要的复杂得多,因为现在必须跟踪两个指针:指向对象的调整指针(破坏构造对象所必需的)和指向内存缓冲区的未调整指针(释放所需的指针)记忆)。

2 个答案:

答案 0 :(得分:1)

我在实践中看到的一个选项是过度分配,然后为自己调整一些东西。

例如,假设您要分配与 M 字节边界对齐的 N 字节。您可以继续分配 N + M-1 字节,然后在分配的空间中找到第一个 M 字节对齐的地址。例如,您可以执行以下操作:

const size_t N = sizeof(Widget);
const size_t M = 64;
char *pc = new char[N+M-1];
char *pc_aligned = (pc+M-1)&(~(M-1));
Widget *p = new (pc_aligned) Widget();    // placement new
// ...
p->~Widget();                             // explicitly call destructor
delete [] pc;                             // delete array allocated with new

答案 1 :(得分:0)

MS明确指出C ++ 11 alignas未在http://msdn.microsoft.com/en-us/library/hh567368.aspx

实施

对于GNU - 如果你把它放在正确的位置似乎是有效的 - 从Where can I use alignas() in C++11?只是一种品味 - 看到更多例子和讨论的答案:

typedef float aligned_block alignas(16) [4];
typedef float aligned_block [4] alignas(16);