当前位置: 首页 > 知识库问答 >
问题:

在C 20d::字符串,它是如何工作的?

那开济
2023-03-14

显然,constexpr std::string尚未添加到GCC的libstdc中(从GCC v11.2开始)。

此代码:

#include <iostream>
#include <string>


int main( )
{
    constexpr std::string str { "Where is the constexpr std::string support?"};

    std::cout << str << '\n';
}

编译

time_measure.cpp:37:31: error: the type 'const string' {aka 'const std::__cxx11::basic_string<char>'} of 'constexpr' variable 'str' is not literal
   37 |         constexpr std::string str { "Where is the constexpr std::string support?"};
      |                               ^~~
In file included from c:\mingw64\include\c++\11.2.0\string:55,
                 from c:\mingw64\include\c++\11.2.0\bits\locale_classes.h:40,
                 from c:\mingw64\include\c++\11.2.0\bits\ios_base.h:41,
                 from c:\mingw64\include\c++\11.2.0\ios:42,
                 from c:\mingw64\include\c++\11.2.0\ostream:38,
                 from c:\mingw64\include\c++\11.2.0\iostream:39,
                 from time_measure.cpp:2:
c:\mingw64\include\c++\11.2.0\bits\basic_string.h:85:11: note: 'std::__cxx11::basic_string<char>' is not literal because:
   85 |     class basic_string
      |           ^~~~~~~~~~~~
c:\mingw64\include\c++\11.2.0\bits\basic_string.h:85:11: note:   'std::__cxx11::basic_string<char>' does not have 'constexpr' destructor

我的问题是,当一个字符串包含超过16chars(因为GCC的SSO缓冲区大小是16)时,这些字符串将如何在引擎盖下工作?有人能给我简单解释一下吗?一个简单的构造函数会在堆栈上创建字符串对象而不使用动态分配吗?

此代码:

    std::cout << "is_trivially_constructible: "
              << std::boolalpha << std::is_trivially_constructible<const std::string>::value << '\n';

打印这个:

is_trivially_constructible: false

现在通过在这里使用Constexpr(显然不使用GCC v11.2编译):

    std::cout << "is_trivially_constructible: "
              << std::boolalpha << std::is_trivially_constructible<constexpr std::string>::value << '\n';

结果是否为true如下所示?

is_trivially_constructible: true

我的目标是做如下事情:

    constexpr std::size_t a { 4 };
    constexpr std::size_t b { 5 };
    constexpr std::string msg { std::format( "{0} + {1} == {2}", a, b, a + b ) };

    std::cout << msg << '\n';

既不std::format也不constepr std::string在GCC v11上编译。2.

共有1个答案

庞鸿骞
2023-03-14

C 20支持在constexpr时间内分配,只要分配在时间常数计算结束时完全解除分配。例如,这个非常愚蠢的例子在C 20中是有效的:

constexpr int f() {
    int* p = new int(42);
    int v = *p;
    delete p;
    return v;
}

static_assert(f() == 42);

但是,如果您忘记删除p在那里,那么f()不再是一个常量表达式。不能泄漏内存。例如,gcc拒绝使用以下内容:

<source>:2:24: error: '(f() == 42)' is not a constant expression because allocated storage has not been deallocated
    2 |     int* p = new int(42);
      |                        ^

回到您的问题,std::string将在constexpr中对长字符串起作用——正如您所期望的那样为其分配内存。但是,C 20 constexpr规则仍然受到此规则的限制,即必须在评估结束前清理所有分配。或者,所有分配都必须是暂时的-C还不支持非暂时的constexpr分配。

结果你原来的程序

int main( )
{
    constexpr std::string str { "Where is the constexpr std::string support?"};
}

是无效的,即使gcc支持Constexpr字符串(就像现在在主干上一样),因为str需要被销毁。但这样就好了:

constexpr int f() {
    std::string s = "Where is the constexpr std::string support?";
    return s.size();
}

static_assert(f() > 16);

然而它不会在C17中编译。

C 23中仍然不支持非瞬态constexpr分配。这是一个非常棘手的问题。但是,希望很快。

 类似资料:
  • 问题内容: 通常,我在互联网上的许多文章中都读到,当我们编写上面的语句时,会创建两个对象。在堆上创建一个String对象,在Literal Pool上创建一个字符串对象。并且堆对象还引用在Literal Pool上创建的对象。(如果我的陈述是错误的,请更正。) 请注意,以上解释是根据我阅读互联网上一些文章后的理解得出的。 所以我的问题是..有什么方法可以停止在文字池中创建字符串对象。怎么做? [请

  • 问题内容: 我有一个通过JSON.Stringify函数从对象转换的json字符串。 我想知道它是json字符串还是普通字符串。 是否有类似“ isJson()”的函数来检查它是否为json? 我想在使用本地存储(如下面的代码)时使用该函数。 先感谢您!! 问题答案: “简单”的方法是在失败时解析并返回未解析的字符串:

  • 我一直在用Swift 3更新我的一些旧代码和答案,但当我使用Swift字符串和子字符串进行索引时,事情变得很混乱。 具体来说,我尝试了以下方法: 第二行给出了以下错误 “String”类型的值没有成员“substringWithRange” 我看到,String现在确实有以下方法: 起初我真的很困惑,所以我开始围绕索引和范围玩。这是子串的后续问答。我在下面添加一个答案来展示它们是如何使用的。

  • 我试图确切地理解Java字符串是如何不可变的。我明白这应该是一个简单的概念,但在阅读了几个在线网页后,我仍然不太明白。 我不明白Java字符串是如何“不可变”的。我目前有以下代码: 我的输出如下: 如果字符串应该是不可变的,为什么会发生这种情况?为什么我能给字符串重新赋值?