我有一个小疑问,但找不到满意的答案。

cppreference提到,如果初始化包含初始化部分,则在 C++20 中使用 constinit 时程序格式不正确。

我只是想知道为什么下面的代码可以编译:

constinit std::string str = "Hello";

由于std::string该类涉及用于存储字符的动态内存分配,因此这似乎是矛盾的。由于动态部分,这不应该被禁止吗?

请就此提供一些指导吗?

提前致谢!

尝试使用标志 -std=C++20 进行编译,程序编译正常,但事实并非如此。

10

  • 5
    如果字符串足够短(“SSO”),则常见std::string实现不会动态分配。由于短度阈值取决于实现,因此您可能不应该依赖它。


    – 

  • @HolyBlackCat 喜欢你的回答。我曾经想过,但想交叉验证一下。这里的功劳全归于你。谢谢


    – 


  • 1
    它被 MSVC 和 gcc 接受(可能是由于上面提到的 SSO),但被 clang 拒绝。参见。增加字符串的大小以通过 SSO 会导致所有 3 个主要编译器出现错误。参见


    – 


  • @wohlstad Clang 18 及更新版本接受它。


    – 

  • 2
    @wohlstad 我确信某个地方会有重复,但显然没有。我会重新发布我的评论作为答案。


    – 


最佳答案
2

std::string如果字符串足够短,常见的实现就不会在堆上分配(这称为“短字符串优化”或“SSO”)。

由于 SSO 中可容纳的字符的确切数量(如果有)取决于实现,因此您可能不应该依赖它,或者至少应该研究三大标准库如何处理这个问题。

这个答案是对@HolyBlackCat答案的补充。

正如那里解释的那样,您成功编译的原因如下:

constinit std::string str = "Hello";

是由于短字符串优化(SSO)。

这两个演示证明了这一点:

  1. 上面这行代码可以在所有 3 个主流编译器上编译。

    参见
  2. 将字符串的大小增加到 SSO 无法处理的范围("Hello1234567890123456789012345678901234567890"在本例中),会导致所有 3 个编译器出现编译错误

    (例如 gcc 问题
    error: 'constinit' variable 'str' does not have a constant initializer:)。

    参见

请注意,SSO 支持的具体长度取决于实现。

在上面的演示中,我只是增加了长度,直到失败。SSO 的最大长度可能会在未来版本中发生变化。