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

时间:2019-10-08 14:18:05

标签: c++ byte language-lawyer c++17

C ++ 17引入了一种新类型std::byte,所以现在我们终于有了一个一流的市民类型来表示内存中的字节。除了标准上的新颖性之外,用于创建对象,生命的开始和结束,别名等的C ++规则在大多数情况下都是相当复杂的,这很直观,因此每当我觉得std::byte是正确的工具时,紧张而又不愿使用它,因为担心会无意间召唤未定义的行为Balrogs。

一种这样的情况是用于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();
}

t2绝对安全并且与t1等效吗?

针对对齐问题,该怎么办?

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

    X* x = new (&buffer) X{};
    x->~X();
}

2 个答案:

答案 0 :(得分:3)

  

t2绝对安全并且与t1等效吗?

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

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

如果您想要适当对齐的存储,请使用std::aligned_storage 参见Barry's answer

答案 1 :(得分:2)

  

t2绝对安全并且与t1等效吗?

不。实际上,两者都是不好的。

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

alignas(X) std::byte storage[sizeof(X)];

t1也存在此问题,因为您几乎可以肯定要写aligned_storage_t<sizeof(X), alignof(X)>而不仅仅是aligned_storage_t<sizeof(X)>。如果X过度对齐,您将在这里丢失它。如果X很大,但是没有对齐要求,那么最终您将获得相对对齐的存储空间。

t1的特殊原因也是不好的:aligned_storage并不能完全保证您认为的保证。特别是,它保证X可以适合aligned_storage<sizeof(X)>,但不能保证它完全适合 specification很简单:

  

成员typedef type应该是普通的标准布局类型,适用于大小最大为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*
};
相关问题