std::byte 可以代替 std::aligned_storage 吗?

bol*_*lov 3 c++ byte language-lawyer c++17

C++17 引入了一种新类型 ,std::byte所以现在我们终于有了一个一等公民类型来表示内存中的字节。除了标准中的新奇之外,对象创建、生命的开始和结束、别名等的 C++ 规则在大多数情况下都相当复杂且不直观,所以每当我觉得std::byte是正确的工具时,我也会感到紧张和不愿使用它,因为害怕无意中召唤出未定义行为炎魔。

一种这样的情况是用于放置 new 的缓冲区:

#include <memory>
#include <cstddef>
#include <type_traits>

struct X { double dummy[4]; char c; };

auto t1()
{
    // the old way

    std::aligned_storage_t<sizeof(X)> buffer;
    X* x = new (&buffer) X{};

    x->~X();
}

auto t2()
{
    // the new way?

    std::byte buffer[sizeof(X)];
    X* x = new (&buffer) X{};

    x->~X();
}
Run Code Online (Sandbox Code Playgroud)

t2完全安全和等效的t1?

针对对齐问题,如何处理:

auto t3()
{
    alignas(X) std::byte buffer[sizeof(X)];

    X* x = new (&buffer) X{};
    x->~X();
}
Run Code Online (Sandbox Code Playgroud)

Bar*_*rry 7

t2完全安全和等效的t1?

不。事实上,两者都不好。

t2不好的原因是NathanOliver指出:它未对齐。你需要写:

alignas(X) std::byte storage[sizeof(X)];
Run Code Online (Sandbox Code Playgroud)

t1也有这个问题,因为你几乎肯定想写aligned_storage_t<sizeof(X), alignof(X)>而不仅仅是aligned_storage_t<sizeof(X)>. 如果X过度对齐,你会在这里失去它。如果X只是大但没有对齐要求,您最终会得到一个相对过度对齐的存储。

t1也有一个特别奇怪的原因:aligned_storage不能完全保证你认为它保证的东西。特别是,它保证 anX可以适合aligned_storage<sizeof(X)>,但不保证它可以完全适合。该规范是简单的:

成员 typedeftype应该是一个普通的标准布局类型,适合用作任何大小至多Len为 Align 的除数的对象的未初始化存储。

也就是说,aligned_storage<16>::type保证至少为 16 个字节,但符合要求的实现可以轻松地为您提供 32. 或 4K。那除了aligned_storage<16>意外使用而不是aligned_storage_t<16>.

这就是P1413作为论文存在的原因:aligned_storage有点糟糕。


所以真正的答案实际上只是写一些像 libstdc++ 的东西__aligned_membuf

template <typename T>
struct storage_for {
    alignas(T) std::byte data[sizeof(T)];

    // some useful constructors and stuff, probably some getter
    // that gives you a T* or a T const*
};
Run Code Online (Sandbox Code Playgroud)


Nat*_*ica 5

完全t2安全并且等同于t1?

不会。 std::aligned_storage创建与放置在其中的对象适当对齐的存储。 std::byte buffer[sizeof(X)]虽然尺寸正确,但对齐方式为std::byte. 这通常不会与您放置在其中的类型具有相同的对齐方式,因为它的对齐方式为1.

对于 C++ 虚拟机而言,这不是问题,但在现实世界中,这可能会导致严重的性能损失,甚至导致程序崩溃。

如果您想要适当对齐的存储,请使用std::aligned_storage查看巴里的答案

  • 这里吐槽:“alignas(alignof(X)) std::byte buffer[sizeof(X)];”怎么样? (2认同)