如何进行c ++对齐的数组分配?

时间:2016-03-06 20:48:07

标签: c++ arrays alignment

我想修改数组分配:

 float * a = new float[n] ;

使用对齐的分配器。我倾向于尝试使用placement new和posix_memalign(或新的c ++ 11等价物),但是看到placement new with arrays is problematic with array allocations,因为compiler may need to have additional storage for count or other metadata

我试过了:

int main()
{
   float * a = new alignas(16) float[3] ;

   a[2] = 0.0 ;

   return a[2] ;
}

但是编译器似乎表明ignoreas被忽略了:

$ g++ -std=c++11 t.cc -Werror
t.cc: In function ‘int main()’:
t.cc:4:39: error: attribute ignored [-Werror=attributes]
    float * a = new alignas(16) float[3] ;
                                       ^
t.cc:4:39: note: an attribute that appertains to a type-specifier is ignored

看起来使用alignas的正确方法是structure declaration declare a structure with alignas,但这只适用于固定大小。

还有一个对齐的存储模板,但我认为这也只适用于固定尺寸。

是否有任何标准方法可以对所有元素调用构造函数进行对齐数组分配?

3 个答案:

答案 0 :(得分:2)

正如其他人所说,不需要支持多种类型。使用前请检查编译器文档。

您可以尝试使用以下方法之一解决问题:

1)根据(desired aligment / sizeof element) - 1分配您的数组并使用std::align。指向libstdc++ implementation

的链接

2)声明一个包含desired aligment / sizeof element元素数组的结构,并按所需的对齐方式对齐。如果你使用这样的结构数组,它应该在内存中给你紧凑的表示,但你将无法使用普通的数组符号或指针算术(因为它(a)未定义的行为,(b)那里是一个很小的机会,他们不会按你的意愿放置)

3)编写自己的对齐分配函数。请注意,您可以添加自己的运算符版本newdelete

namespace my
{
    struct aligned_allocator_tag {};
    aligned_allocator_tag aligned;
}

void* operator new( std::size_t count, my::aligned_allocator_tag, std::size_t aligment);
void* operator new[]( std::size_t count, my::aligned_allocator_tag, std::size_t aligment)
{
    return ::operator new(count, my::aligned, aligment);
}
//Usage
foo* c = new(my::aligned, 16) foo[20];

您将需要分配内存,保留足够的空间来存储原始指针(由malloc / what返回)或指定的字节数量被移位,因此后续删除将释放corect指针,将指针对齐到所需大小并返回它。

以下是an answerand another one,其中显示了如何对齐内存。

请注意,这两个答案都使用实现定义的行为,对转换为整数的指针进行逐位算术并将其转换回来。唯一真正完全标准的方法是将内存转换为char*并添加其值与下一个对齐的地址之间的差异。

如果你可以使用一些非标准的内存分配函数,你也可以将它们包装到自定义运算符new中。

答案 1 :(得分:1)

基本上,你被困了,因为,在[expr.new]:

  

实现定义是否支持过度对齐类型。

有一个proposal可以更好地支持这一点。在此之前,如果您想要执行您要执行的操作,则必须使用aligned_alloc而不是new

如果你将数组放在结构中:

struct S {
    alignas(16) float _[3];
};

然后new S将为_提供正确的对齐方式,但不一定适用于S本身。这可能就足够了。如果没有,那么您可以在operator new()本身上重载operator delete()S以保证正确的行为。

答案 2 :(得分:0)

C ++中对齐的原生支持仍然令人沮丧。从它的外观来看,你正在调整一个4浮点向量,这样你就不会错过C ++ 14不能比16字节对齐做得更好的危险,但即便如此,它还是&# #39;不是所有C ++ 14编译器都可靠支持的功能。如果您需要使用new float[]的可移植代码,那么您就已经失去了竞争。

我认为在当前标准中你能得到的最接近的是创建一个矢量大小和矢量对齐的数据类型(例如用std :: aligned_storage),然后养成使用它的习惯,而不是单个浮点数组,用于矢量数学。如果你需要可变长度向量,那么你必须向上舍入到最接近的4个浮点数。

(对不起,这不是你想要的答案,但我认为这是你向前迈进所需要的答案。)