为什么 std::string 在索引超出范围时不自动追加(或崩溃)?

Why doesn't std::string automatically append (or crash) when the index is out of range?

本文关键字:追加 崩溃 string std 索引 范围 为什么      更新时间:2023-10-16

我是C++新手,我有一些 C 经验,我很高兴看到 std::string 作为 char[] 的替代品。在我的学习过程中,我写了一个看起来像这样的函数:

std::string constToLowercase(const std::string &s){
std::string newString = "";
for (int i = 0; i < s.length(); i++){
newString[i] = tolower(s[i]);
}
return(newString);
}

目标是接受字符串并返回小写版本,而不会影响原始字符串。 我发现这个函数总是返回一个空字符串。我想这是因为我正在索引到字符串尚未保留的内存中,但我本来希望出现异常或程序崩溃,而不是简单地返回任何内容。

我的下一个想法是尝试这个(在第 2 行更改):

std::string constToLowercase(const std::string &s){
std::string newString = s;
for (int i = 0; i < s.length(); i++){
newString[i] = tolower(s[i]);
}
return(newString);
}

这是成功的,显然是解决我问题的好方法。

不过,我对自己的缺乏理解感到不安,在试图弄清楚为什么我的原始功能不起作用时,我尝试了这个(第 2 行的更改已还原,第 4 行的更改):

std::string constToLowercase(const std::string &s){
std::string newString = "";
for (int i = 0; i < s.length(); i++){
newString = newString + static_cast<char>(tolower(s[i]));
}
return(newString);
}

这个函数按照我预期的函数 1 工作。我的问题是为什么函数 1 不像函数 3?作为后续行动,为什么函数 1 不会崩溃?

C++尝试为您提供具有更高级别类型的原始 C 级性能。

它将某些内容保留为未定义的行为,并且不检查边界,因为这会减慢速度。

通常有一些 API 更安全,例如在越界时抛出的.at

还有别的东西 - 它应该用什么填充? (一个空间? 空? 它应该如何处理访问元素2^60? 这些都是很难完美回答的问题。

您可以轻松编写自己的函数,完全按照自己的要求执行。 这并不难。 然而,如果他们把它烤成std::string,你将永远无法获得"原始金属"的性能。

我的问题是为什么函数 1 不像函数 3?

因为std::basic_string::operator[]的文档是这样说的:

返回对指定位置处字符的引用。 不执行边界检查。如果 pos> size(),则行为未定义

作为后续行动,为什么函数 1 不会崩溃?

因为未定义的行为并不意味着崩溃。它可能会崩溃,也可能不会。它肯定不会做什么 - 始终正常工作。