静态向量内部数据布局 - `union` vs`std :: aligned_storage_t` - 巨大的性能差异

Vit*_*meo 20 c++ optimization unions language-lawyer c++17

假设您必须实现一个static_vector<T, N>类,它是一个完全存在于堆栈中并且永远不会分配的固定容量容器,并且公开std::vector类似接口.(Boost提供boost::static_vector.)

考虑到我们必须为最大实例提供未初始化的存储,在设计内部数据布局时可以有多种选择:NT

无论选择如何,创建成员都需要使用"放置new",访问它们将需要一些东西reinterpret_cast.


现在假设我们有两个非常小的实现static_vector<T, N>:

  • with_union:使用"单一成员union"方法实施;

  • with_storage:使用"单一std::aligned_storage_t"方法实施.

让我们使用both g++clang++with 执行以下基准测试-O3.我使用quick-bench.com完成这项任务:

void escape(void* p) { asm volatile("" : : "g"(p) : "memory"); }
void clobber()       { asm volatile("" : :        : "memory"); }

template <typename Vector>
void test()
{
    for(std::size_t j = 0; j < 10; ++j)
    {
        clobber();
        Vector v;
        for(int i = 0; i < 123456; ++i) v.emplace_back(i);
        escape(&v);
    }
}
Run Code Online (Sandbox Code Playgroud)

(escapeclobber从钱德勒卡鲁斯的CppCon 2015年采取的谈话:"调整C++:基准,并且CPU和编译器哦,我的!")

g ++结果

clang ++结果


从结果中可以看出,g++似乎能够积极地优化(矢量化)使用"单一std::aligned_storage_t"方法的实现,而不是使用的实现union.

我的问题是:

  • 标准中是否存在任何阻止实施使用的union积极优化? (即标准在使用时为编译器授予更多自由std::aligned_storage_t- 如果是,为什么?)

  • 这纯粹是"实施质量"问题吗?

Bar*_*rry 11

xskxzr是对的,这个问题与此问题相同.从根本上说,gcc错失了一个忘记std::array数据一致的优化机会.John Zwinck帮助报告了错误80561.

您可以通过对以下两项更改中的一项进行验证来验证此基准with_union:

  1. 改变_datastd::array<U, N>简单一个U[N].性能变得相同

  2. _data通过将实现更改emplace_back()为:提醒实际对齐的gcc :

    template <typename... Ts> 
    T& emplace_back(Ts&&... xs)
    {
        U* data = static_cast<U*>(__builtin_assume_aligned(_data.data(), alignof(U)));
        T* ptr = &data[_size++]._x;
        return *(new (ptr) T{std::forward<Ts>(xs)...});
    }
    
    Run Code Online (Sandbox Code Playgroud)

无论是与你的标杆,其余的变化让我之间比较的结果WithUnionWithAlignedStorage.