我创建了简单的C ++ std::string值。
但是该值会产生意想不到的结果。
我使用g ++编译器(Linux)和Visual Studio(Windows)测试了此代码,并且两个编译器都出现相同的问题。
正常结果码
/* This code results are Normal */
#include <bits/stdc++.h>
int main() {
std::string a1 = "a1";
std::string a2 = "a2";
std::string b1("b1");
std::string b2("b2");
const char *c1 = std::string("c1").c_str();
const char *c2 = std::string("c2").c_str();
std::cout << "Expected [a1], real [" << a1 << "]\n";
std::cout << "Expected [a2], real [" << a2 << "]\n";
std::cout << "Expected [b1], real [" << b1 << "]\n";
std::cout << "Expected [b2], real [" << b2 << "]\n";
std::cout << "Expected [c1], real [" << c1 << "]\n";
std::cout << "Expected [c2], real [" << c2 << "]\n";
}
Run Code Online (Sandbox Code Playgroud)
控制台结果:
Expected [a1], real [a1]
Expected [a2], real [a2]
Expected [b1], real [b1]
Expected [b2], real [b2]
Expected [c1], real [c1]
Expected [c2], real [c2]
Run Code Online (Sandbox Code Playgroud)
结果代码异常
/* This code results are Normal */
#include <bits/stdc++.h>
int main() {
std::string a1 = "a1";
std::string a2 = "a2";
std::string b1("b1");
std::string b2("b2");
const char *c1 = std::string("c1").c_str();
const char *c2 = std::string("c2").c_str();
std::cout << "Expected [a1], real [" << a1 << "]\n";
std::cout << "Expected [a2], real [" << a2 << "]\n";
std::cout << "Expected [b1], real [" << b1 << "]\n";
std::cout << "Expected [b2], real [" << b2 << "]\n";
std::cout << "Expected [c1], real [" << c1 << "]\n";
std::cout << "Expected [c2], real [" << c2 << "]\n";
}
Run Code Online (Sandbox Code Playgroud)
控制台结果:
Expected [a1], real [a1]
Expected [a2], real [a2]
Expected [b1], real [b1]
Expected [b2], real [b2]
Expected [c1], real [b2]
Expected [c2], real [b2]
Run Code Online (Sandbox Code Playgroud)
我通常只使用string str = "",但是我想知道何时进行测试。
我认为构造函数应该有一个问题。
我如何理解std :: string的异常结果?
问题就在这里
const char *c1 = std::string("c1").c_str();
const char *c2 = std::string("c2").c_str();
Run Code Online (Sandbox Code Playgroud)
您在这里所做的是在每一行中创建一个临时std::string对象,获取指向其内容的指针,并将该指针分配给变量。在每一行的末尾,临时项std::string将被销毁,而您通过的指针.c_str()将因此成为悬空的指针 ……
通常,两个版本的代码都具有未定义的行为。这仅意味着:您编写的代码违反了允许编译器进行工作的基本假设(例如,如果您决定取消引用指针,则该指针实际上指向有效对象),因此,编译器不能期望以某种方式神奇地产生一个有意义的程序。关于第一个版本为何“起作用”(即似乎起作用)而第二个版本与编译器将C ++代码转换成何种机器代码无关的确切解释。通常,请注意,在第二个版本中,您的两个临时字符串是要构造的第一个字符串。一旦这些临时字符串被销毁,可以为它们分配的任何内存都可以用于以后创建的字符串。另一方面,在您的第一个示例中,您的临时字符串是要构造的最后一个字符串。临时字符串销毁后,将不再构造需要内存的其他本地对象。因此,您的两个指针所指向的内存内容不会被覆盖的可能性不大。因此,尽管您的指针将不再是有效的指针,并且将不允许访问它们指向的对象(因为这些对象不再存在),但是无论如何这样做仍然可能会产生预期的结果。不会被覆盖。因此,尽管您的指针将不再是有效的指针,并且将不允许访问它们指向的对象(因为这些对象不再存在),但是无论如何这样做仍然可能会产生预期的结果。不会被覆盖。因此,尽管您的指针将不再是有效的指针,并且将不允许访问它们指向的对象(因为这些对象不再存在),但是无论如何这样做仍然可能会产生预期的结果。
由于您没有说明使用的确切编译器版本和编译选项,因此很难确切说明您的编译器在做什么。但是,让我们看一下最新的GCC在优化级别上会做什么-O2(我无法仅使用默认设置来重现该问题)。当前GCC版本使用的标准库默认情况下执行短字符串优化。每个有问题的字符串只有两个字符长。因此,std::string对象的内部缓冲区及其结果.c_str()实际上将位于std::string堆栈上的对象内部。查看第一和第二个组件上面的代码版本,我们看到编译器确实在第一个版本中确实将临时字符串放在堆栈的两个单独位置,而将它们放在同一位置,随后b2在第二个版本中构造了字符串……