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)
是
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)>,但不保证它可以完全适合。该规范是简单的:
成员 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*
};
Run Code Online (Sandbox Code Playgroud)
完全
t2安全并且等同于t1?
不会。 std::aligned_storage创建与放置在其中的对象适当对齐的存储。 std::byte buffer[sizeof(X)]虽然尺寸正确,但对齐方式为std::byte. 这通常不会与您放置在其中的类型具有相同的对齐方式,因为它的对齐方式为1.
对于 C++ 虚拟机而言,这不是问题,但在现实世界中,这可能会导致严重的性能损失,甚至导致程序崩溃。
如果您想要适当对齐的存储,请使用查看巴里的答案std::aligned_storage
| 归档时间: |
|
| 查看次数: |
638 次 |
| 最近记录: |