C++:为什么这个字符串输入失败,而另一个没有
C++: Why does this string input fail while the other does not
我从朋友那里得到了这个问题
#include <string>
#include <vector>
#include <iostream>
void riddle(std::string input)
{
auto strings = std::vector<std::string>{};
strings.push_back(input);
auto raw = strings[0].c_str();
strings.emplace_back("dummy");
std::cout << raw << "n";
}
int main()
{
riddle("Hello world of!"); // Why does this print garbage?
//riddle("Always look at the bright side of life!"); // And why doesn't this?
std::cin.get();
}
我的第一个观察是,当传递到input
的单词数超过 3 个单词时,riddle()
函数不会产生垃圾。我仍在试图了解为什么第一种情况失败而不是第二种情况失败。无论如何,认为这很有趣。
这是未定义的行为 (UB),这意味着任何事情都可能发生,包括代码工作。 它是 UB,因为emplace_back
使指向向量中对象的所有指针无效。发生这种情况是因为向量可能会被重新分配(显然是这样)。
UB 的第一种情况由于短字符串优化 (sso) 而"不起作用"。由于 sso,原始指针指向由矢量直接分配的内存,该内存在重新分配后丢失。
UB 的第二种情况"有效",因为字符串文本对于 SSO 来说太长并且驻留在独立的内存块上。在调整大小期间,字符串对象将从中移动,将文本内存块的所有权移动到新创建的字符串对象。由于内存块只是更改了所有权,因此它在emplace_back
后仍然有效。
std::string::c_str()
:
返回的指针可能会因进一步调用修改对象的其他成员函数而失效。
std::vector::emplace_back
:
如果发生重新分配,则会修改所有包含的元素。
由于无法知道在调用emplace_back
时是否会发生vector
重新分配,因此您必须假设随后使用string::c_str()
的早期返回值会导致未定义的行为。
由于未定义的行为是 - 未定义 - 任何事情都可能发生。 因此,您的代码可能看起来有效,也可能似乎失败。 无论哪种方式都是错误的。
相关文章:
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 运行同一解决方案的另一个项目的项目
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- C++从另一个类访问公共静态向量的正确方法是什么
- C++-试图将函数指针推回到另一个CPP文件中的矢量时出错
- 使用std::transform将一个范围的元素添加到另一个范围中
- 输入到文件并输出到另一个文件,并将流文件传递给函数
- 我可以将一个用clang c++11编译的对象与另一个用c++17编译的对象链接起来吗
- 修改函数中的指针(将另一个指针作为参数传递)
- 为什么我不能将一个对象push_back到属于另一个类的对象向量中?
- C++试图读取一个文件并输出到另一个文本文件
- 两个线程一个使用流 Api,另一个线程创建文件失败并出现错误ERROR_SHARING_VIOLATION
- xcb_get_image_reply另一个工作区/桌面上的窗口失败
- C++:为什么这个字符串输入失败,而另一个没有
- 类模板中的 typedef 的 SFINAE 失败是指另一个类模板中的 typedef
- C++宏在子类未使用另一个宏时失败
- 为什么当在另一个文件中更改外部常量时,链接器不会失败
- c++从另一个对象赋值失败
- 为什么一个代码编译了,另一个却失败了