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

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

constinit std::string str = "Hello";

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

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

3

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


    – 


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


    – 

  • @HolyBlackCat 我现在明白了。无论如何,我使用更长的字符串(超过 SSO 可以处理的范围)更新了我的评论,这在所有 3 个方面都失败了,这加强了你的洞察力。


    – 



最佳答案
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 的最大长度可能会在未来版本中发生变化。