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

问题描述 投票:0回答:2

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

t2
完全安全且与
t1
等效吗?

针对对齐问题,如何:

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

    X* x = new (&buffer) X{};
    x->~X();
}
c++ c++17 language-lawyer byte std-byte
2个回答
9
投票

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)>
,但不能保证它可以完全适合规格很简单:

成员 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*
};

4
投票

t2
完全安全且与
t1
等效吗?

不。

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

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

如果您想要适当对齐的存储,使用

std::aligned_storage
请参阅Barry的答案

© www.soinside.com 2019 - 2024. All rights reserved.