【问题标题】:Can std::byte replace std::aligned_storage?std::byte 可以替换 std::aligned_storage 吗?
【发布时间】:2019-10-08 23:06:21
【问题描述】:

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

一个这样的情况是用于放置新的缓冲区:

#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();
}

【问题讨论】:

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


    【解决方案1】:

    t2 是否完全安全并等同于 t1

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

    t2 不好,因为NathanOliver 表示:它未对齐。你需要写:

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

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

    t1 也因为一个特别特殊的原因而不好:aligned_storage 并不能完全保证您认为它所保证的内容。特别是,它保证X 可以适合aligned_storage&lt;sizeof(X)&gt;,但不保证它可以完全适合specification 很简单:

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

    也就是说,aligned_storage&lt;16&gt;::type 保证至少为 16 个字节,但符合要求的实现很容易为您提供 32. 或 4K。除了不小心使用aligned_storage&lt;16&gt;而不是aligned_storage_t&lt;16&gt;的问题。

    这就是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*
    };
    

    【讨论】:

      【解决方案2】:

      t2 是否完全安全且等同于 t1

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

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

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

      【讨论】:

      • 在这里吐口水:alignas(alignof(X)) std::byte buffer[sizeof(X)]; 呢?
      • @bolov 那没问题。不过,这比 std::aligned_storage_t&lt;sizeof(X)&gt; buffer 打字要多得多。
      • @NathanOliver:但它可能会更好,因为alignof(X) 可能远小于aligned_storage 在未指定对齐方式时为您提供的默认对齐方式。
      • @NicolBolas 为此,您可以使用std::aligned_storage_t&lt;sizeof(X), alignof(X)&gt; buffer
      • @NathanOliver:另外,aligned_storage/union are being deprecated 在 C++20 或 23 中。
      猜你喜欢
      • 2015-08-31
      • 2020-01-23
      • 2013-10-18
      • 2015-03-27
      • 2013-03-05
      • 2017-05-14
      • 1970-01-01
      • 2016-02-12
      • 2021-05-17
      相关资源
      最近更新 更多