24

是否有任何可移植的方法来确定任何类型的最大可能对齐方式是多少?

例如在 x86 上,SSE 指令需要 16 字节对齐,但据我所知,没有指令需要更多,因此任何类型都可以安全地存储到 16 字节对齐的缓冲区中。

我需要创建一个缓冲区(例如 char 数组),我可以在其中写入任意类型的对象,因此我需要能够依赖缓冲区的开头进行对齐。

如果一切都失败了,我知道分配一个 char 数组new可以保证最大对齐,但是使用 TR1/C++0x 模板alignment_ofaligned_storage,我想知道是否可以在我的缓冲区中就地创建缓冲区类,而不是需要动态分配数组的额外指针间接。

想法?

我意识到有很多选项可以确定一组有界类型的最大对齐方式:联合,或者只是alignment_of来自 TR1,但我的问题是类型集是无界的。我事先不知道哪些对象必须存储到缓冲区中。

4

6 回答 6

15

在 C++11 中,头文件 cstddef 中定义的 std::max_align_t 是一种 POD 类型,其对齐要求至少与每个标量类型的对齐要求一样严格(一样大)。

使用新的 alignof 运算符,它就像alignof(std::max_align_t)

于 2013-04-17T23:06:24.443 回答
11

在 C++0x 中,Align模板参数的std::aligned_storage<Len, Align>默认参数为“default-alignment”,其定义为(N3225 §20.7.6.6 表 56):

对于大小不大于 的任何 C++ 对象类型,default-alignment 的值应是最严格的对齐要求Len

目前尚不清楚 SSE 类型是否会被视为“C++ 对象类型”。

默认参数不是 TR1 的一部分aligned_storage;它是为 C++0x 添加的。

于 2010-12-30T16:42:33.103 回答
7

不幸的是,确保最大对齐比它应该的要困难得多,并且没有保证的解决方案 AFAIK。来自GotW博客(Fast Pimpl 文章):

union max_align {
  short       dummy0;
  long        dummy1;
  double      dummy2;
  long double dummy3;
  void*       dummy4;
  /*...and pointers to functions, pointers to
       member functions, pointers to member data,
       pointers to classes, eye of newt, ...*/
};

union {
  max_align m;
  char x_[sizeofx];
};

这不能保证是完全可移植的,但实际上它已经足够接近了,因为很少或没有系统不能按预期工作。

那是我所知道的最接近的“黑客”。

还有另一种我个人用于超快速分配的方法。请注意,这是邪恶的,但我在光线追踪领域工作,其中速度是衡量质量的最大指标之一,我们每天都会分析代码。它涉及使用具有预分配内存的堆分配器,其工作方式类似于本地堆栈(只是在分配时增加一个指针,在解除分配时减少一个)。

我特别将它用于Pimpls。然而,仅仅拥有分配器是不够的;为了让这样的分配器工作,我们必须假设类 Foo 的内存是在构造函数中分配的,同样的内存同样只在析构函数中被释放,并且 Foo 本身是在堆栈上创建的。为了安全起见,我需要一个函数来查看类的“this”指针是否在本地堆栈上,以确定我们是否可以使用我们的超快速基于堆的堆栈分配器。为此,我们必须研究特定于操作系统的解决方案:我将TIBTEB用于 Win32/Win64,我的同事找到了适用于 Linux 和 Mac OS X 的解决方案。

经过一周研究特定于操作系统的方法来检测堆栈范围、对齐要求并进行大量测试和分析后,结果是一个分配器可以根据我们的滴答计数器基准在 4 个时钟周期内分配内存,而不是大约malloc/operator new 需要 400 个周期(我们的测试涉及线程争用,因此在单线程情况下 malloc 可能会比这快一点,可能是几百个周期)。我们添加了每个线程的堆堆栈并检测到正在使用哪个线程,这将时间增加到大约 12 个周期,尽管客户端可以跟踪线程分配器以获得 4 个周期的分配。它从地图上清除了基于内存分配的热点。

虽然您不必经历所有这些麻烦,但编写一个快速分配器可能比max_align这里更容易并且更普遍适用(例如:允许在运行时确定分配/释放的内存量)。max_align很容易使用,但是如果你追求内存分配的速度(假设你已经分析了你的代码并在 malloc/free/operator new/delete 中找到了热点,而主要贡献者在你可以控制的代码中),编写自己的分配器确实可以有所作为。

于 2010-06-27T09:43:52.913 回答
5

maximally_aligned_t缺少所有编译器都忠实承诺支持所有架构的某种类型,我看不出如何在编译时解决这个问题。正如您所说,潜在类型的集合是无限的。额外的指针间接真的有那么大吗?

于 2009-10-06T19:59:06.740 回答
1

分配对齐的内存比看起来更棘手 - 参见示例对齐内存分配的实现

于 2009-10-06T20:00:03.290 回答
-2

这就是我正在使用的。除此之外,如果您正在分配内存,则长度大于或等于 max_alignment 的 new() 的 char 数组将与 max_alignment 对齐,因此您可以使用该数组的索引来获取对齐的地址。

enum {
            max_alignment = boost::mpl::deref<
                boost::mpl::max_element<
                        boost::mpl::vector<
                            boost::mpl::int_<boost::alignment_of<signed char>::value>::type,
                            boost::mpl::int_<boost::alignment_of<short int>::value>::type,
                            boost::mpl::int_<boost::alignment_of<int>::value>::type,                                boost::mpl::int_<boost::alignment_of<long int>::value>::type,
                            boost::mpl::int_<boost::alignment_of<float>::value>::type,
                            boost::mpl::int_<boost::alignment_of<double>::value>::type,
                            boost::mpl::int_<boost::alignment_of<long double>::value>::type,
                            boost::mpl::int_<boost::alignment_of<void*>::value>::type
                        >::type
                    >::type
                >::type::value
            };
        }
于 2012-03-20T22:46:53.313 回答