【问题标题】:How to do c++ aligned array allocation?如何进行 C++ 对齐数组分配?
【发布时间】:2016-06-20 07:57:14
【问题描述】:

我想修改一个数组分配:

 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] ;
}

但编译器似乎表明忽略了对齐:

$ 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 中,但这仅适用于固定大小。

还有一个aligned_storage 模板,但我认为它也只适用于固定大小。

是否有任何标准方法来执行对齐数组分配,将调用所有元素的构造函数?

【问题讨论】:

    标签: c++ arrays alignment


    【解决方案1】:

    正如其他人所说,不需要支持过度对齐的类型。在使用之前检查你的编译器文档。

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

    1) 过度分配你的数组((desired aligment / sizeof element) - 1)并使用std::alignlibstdc++ 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/whatever 返回)或指针被移位的字节数,因此后续删除将释放正确的指针,将指针对齐到所需的大小并返回它。

    这里是an answerand another one,展示了如何对齐内存。

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

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

    【讨论】:

      【解决方案2】:

      基本上,您被卡住了,因为在 [expr.new] 中:

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

      有一个proposal 可以更好地支持这一点。在那之前,如果你想做你想做的事,你必须使用aligned_alloc而不是new


      如果你把你的数组放在一个结构中:

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

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

      【讨论】:

      • aligned_alloc 似乎是 C11 构造。你如何测试它是否可用?
      【解决方案3】:

      C++ 中对对齐的原生支持仍然令人沮丧。从外观上看,您正在对齐一个 4 浮点向量,因此您错过了 C++14 不能比 16 字节对齐更好的危险,但即便如此,它也不是一个可靠支持的功能所有 C++14 编译器。如果您需要使用 new float[] 的可移植代码,那么您就已经输掉了比赛。

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

      (抱歉,这不是您想要的答案,但我认为这是您前进所需的答案。)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-22
        • 2018-12-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-08
        • 2023-01-24
        • 1970-01-01
        相关资源
        最近更新 更多