为什么 std::aligned_storage 在 C++23 中被弃用以及使用什么替代?

发布于 2025-01-20 11:50:38 字数 585 浏览 6 评论 0原文

我刚刚看到C ++ 23计划将两者都弃用 std :: aligned_storage 和std :: aligned_storage_t以及 std :: Aligned_unionstd :: aligned_union_t

据我所知,在对齐存储中的新对象并不是特别constexpr友好,但这似乎不是完全抛出类型的好理由。这使我假设使用std :: aligned_storage和我不知道的朋友还有其他一些基本问题。那会是什么?

还有这些类型的拟议替代方案吗?

I just saw that C++23 plans to deprecate both std::aligned_storage and std::aligned_storage_t as well as std::aligned_union and std::aligned_union_t.

Placement new'd objects in aligned storage are not particularly constexpr friendly as far as I understand, but that doesn't appear to be a good reason to throw out the type completely. This leads me to assume that there is some other fundamental problem with using std::aligned_storage and friends that I am not aware of. What would that be?

And is there a proposed alternative to these types?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

国产ˉ祖宗 2025-01-27 11:50:38

以下是 P1413R3

背景

aligned_* 对代码库有害,不应使用。在高层次上:

  • 使用 aligned_* 会调用未定义的行为(类型无法提供存储。)
  • 这些保证不正确(标准只要求类型至少与请求的大小一样大,但没有设置大小上限。)
  • 由于多种原因,API 是错误的(参见“关于 API”。)
  • 由于 API 是错误的,所以几乎所有用法都涉及相同的重复准备工作(请参阅“现有用法”。)

关于 API

std::aligned_* 遭受许多糟糕的 API 设计决策的困扰。其中一些是共享的,一些是特定的。至于分享的内容,主要存在三个问题[为了简洁起见,这里仅包含一个问题]

  • 需要使用 reinterpret_cast 来访问该值

std::aligned_* 实例上没有 .data(),甚至没有 .data
相反,API 要求您获取对象的地址,用它调用 reinterpret_cast(...),然后
最后间接产生的指针给你一个T&。这不仅意味着它不能在 constexpr 中使用,而且
在运行时,很容易意外调用未定义的行为。 reinterpret_cast 是使用要求
API 的错误是不可接受的。


建议更换

aligned_* 最简单的替代实际上不是库功能。相反,用户应该使用正确对齐的
std::byte 数组,可能会调用 std::max(std::initializer_list) 。这些可以在
分别是 标头(本节末尾有示例)。
不幸的是,这种替代并不理想。要访问 aligned_* 的值,用户必须调用 reinterpret_cast
将字节读取为 T 实例的地址。使用字节数组作为替代并不能避免这个问题。也就是说,重要的是要认识到,在已经存在的地方继续使用reinterpret_cast并不比在以前不存在的地方新引入它那么糟糕。 ...

上述部分来自已接受的退休 aligned_* 提案,后面是许多示例,例如这两个替换建议:

// To replace std::aligned_storage
template <typename T>
class MyContainer {
private:
    //std::aligned_storage_t<sizeof(T), alignof(T)> t_buff;
    alignas(T) std::byte t_buff[sizeof(T)];
};
// To replace std::aligned_union
template <typename... Ts>
class MyContainer {
private:
    //std::aligned_union_t<0, Ts...> t_buff;
    alignas(Ts...) std::byte t_buff[std::max({sizeof(Ts)...})];
};

Here are three excerpts from P1413R3:

Background

aligned_* are harmful to codebases and should not be used. At a high level:

  • Using aligned_* invokes undefined behavior (The types cannot provide storage.)
  • The guarantees are incorrect (The standard only requires that the type be at least as large as requested but does not put an upper bound on the size.)
  • The API is wrong for a plethora of reasons (See "On the API".)
  • Because the API is wrong, almost all usage involves the same repeated pre-work (See "Existing usage".)

On the API

std::aligned_* suffer from many poor API design decisions. Some of these are shared, and some are specific to each. As for what is shared, there are three main problems [only one is included here for brevity]:

  • Using reinterpret_cast is required to access the value

There is no .data() or even .data on std::aligned_* instances.
Instead, the API requires you to take the address of the object, call reinterpret_cast<T*>(...) with it, and then
finally indirect the resulting pointer giving you a T&. Not only does this mean that it cannot be used in constexpr, but
at runtime it's much easier to accidentally invoke undefined behavior. reinterpret_cast being a requirement for use
of an API is unacceptable.


Suggested replacement

The easiest replacement for aligned_* is actually not a library feature. Instead, users should use a properly-aligned
array of std::byte, potentially with a call to std::max(std::initializer_list<T>) . These can be found in the
<cstddef> and <algorithm> headers, respectively (with examples at the end of this section).
Unfortunately, this replacement is not ideal. To access the value of aligned_*, users must call reinterpret_cast on
the address to read the bytes as T instances. Using a byte array as a replacement does not avoid this problem. That said, it's important to recognize that continuing to use reinterpret_cast where it already exists is not nearly as bad as newly introducing it where it was previously not present. ...

The above section from the accepted proposal to retire aligned_* is then followed with a number of examples, like these two replacement suggestions:

// To replace std::aligned_storage
template <typename T>
class MyContainer {
private:
    //std::aligned_storage_t<sizeof(T), alignof(T)> t_buff;
    alignas(T) std::byte t_buff[sizeof(T)];
};
// To replace std::aligned_union
template <typename... Ts>
class MyContainer {
private:
    //std::aligned_union_t<0, Ts...> t_buff;
    alignas(Ts...) std::byte t_buff[std::max({sizeof(Ts)...})];
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文