使用std::aligned_storage对齐静态数组

6

我正在尝试使用std::aligned_storage模式实现简单静态数组的16字节对齐:

#include <type_traits>
int main()
{
    const size_t SIZE = 8;
    using float_16 = std::aligned_storage<sizeof(float) * SIZE, 16>::type;
    float_16 mas;
    new(&mas) float[SIZE];//Placement new. Is this necessary? 

    mas[0]=1.f;//Compile error while attempting to set elements of aligned array
}

我遇到了以下编译错误:

在“mas[0]”中没有匹配的“operator[]”

然后我尝试使用显式指针转换:
float* mas_ = reinterpret_cast<float*>(mas); 

但是这也导致了编译错误:

从类型“float_16 {aka std::aligned_storage<32u, 16u>::type}”到类型“float*”的转换无效

有人能建议我如何正确地使用std::aligned_storage来对齐静态数组吗?


为什么不使用new返回的指针? - avakar
2
@avakar:new返回的指针没有扩展对齐方式。 - R. Martinho Fernandes
@R.MartinhoFernandes:我认为avakar谈论的是放置new(它是对齐的)。 (请参阅我的回答) - Jarod42
@R.MartinhoFernandes,Jarod42是正确的,我自然而然地在谈论原始问题中的放置new。 - avakar
3个回答

8

你可以使用以下方法:

float* floats = new (&mas) float[SIZE];

然后你可以使用:

floats[0] = 1.f;

完全没有reinterpret_cast :)


我会担心使用放置 new 进行数组分配,因为分配可能需要额外的空间来跟踪分配大小,这是实现定义的。 - Fabio A.
@FabioA.:确实,为了完全安全,我们必须循环使用SIZE个placement new :( 或者使用std::array<float, SIZE>或类似的方法。 - Jarod42

5
mas不是指针。 reinterpret_cast 必须仅涉及指针、引用或整数类型,并且仅限于某些组合:指向和从整数类型的指针、指向指针的指针、引用到引用、或者整数类型到它自身。在这种情况下,您正在尝试将std :: aligned_storage<32u,16u> :: type 转换为指针。您可以从中获得的最好结果是一个指针的引用转换,但是这是不允许的†。

尝试将其地址转换为另一种指针类型:reinterpret_cast<float*>(& mas);


† 有趣的是:如果 std :: aligned_storage<32u,16u> :: type 是指针类型,则会得到最差的结果。这是可疑的,因为32字节指针并不常见,但是在非常恶劣的标准库中(如Hell ++),可能会发生这种情况,例如,对于 std :: aligned_storage<8u,8u> :: type 。那么,在Hell ++中,它将编译通过,然后您将把指针类型转换为另一种指针类型,然后对其进行所有污点操作,如取消引用它。这将是灾难性的,因为如果 std :: aligned_storage<32u,16u> :: type 是指针类型,则对象将没有存储的地址,而是将成为存储。


它可以工作,但我能确定mas_确实是16字节对齐的吗? - gorill
2
@gorill 如果不是这样,请为您的标准库实现提交错误报告。(您可以通过将指针重新解释为整数并检查它是否可被16整除来进行测试) - R. Martinho Fernandes
reinterpret_cast<float*&>(mas) 将会把 mas 的位模式解释为一个指针 - 这不是预期的结果。请使用 reinterpret_cast<float*>(&mas) 代替。 - Sebastian Redl
@SebastianRedl 哦,对了!他想要一个数组,不是指针。糟糕。谢谢。(现在我感到有点傻,在这里发布那个注释并引起同样的事情) - R. Martinho Fernandes
5
哦,请原谅我的直言。在你开始涉足“reinterpret_cast”和“aligned_storage”的领域之前,你需要先学习一些基本的C++知识。 - R. Martinho Fernandes
显示剩余3条评论

3

只要去做

alignas(16) float mas[SIZE];

"std::aligned_storage 是一个来自于 boost 的 C++03 遗物。"

1
@gorill 是的,4.7版本不支持。尝试将编译器升级到4.8。 - user1095108
3
aligned_storage 不是 C++03 的遗物。它用于对齐原始存储,而 alignas 用于对齐对象。这些有不同的目的。虽然在这个特定的情况下它并没有太大的区别,但 aligned_storage 提供了非冗余的功能。 - R. Martinho Fernandes
@R.MartinhoFernandes 这些都可以用 typedef 或者 using 来替代。 - user1095108

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接