c++ std::string 意外更改。我认为这个问题是关于深拷贝和浅拷贝

c++ std::string changed unexpected. I think this problem is about deep & shallow copy

我创建了简单的 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";
}

控制台结果:

Expected [a1], real [a1]
Expected [a2], real [a2]
Expected [b1], real [b1]
Expected [b2], real [b2]
Expected [c1], real [c1]
Expected [c2], real [c2]

结果代码异常

/* This code results has some problem. */

#include <bits/stdc++.h>

int main() {

    const char *c1 = std::string("c1").c_str();
    const char *c2 = std::string("c2").c_str();

    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"; // c1 = b2?
    std::cout << "Expected [c2], real [" << c2 << "]\n"; // b2 = b2?
}

控制台结果:

Expected [a1], real [a1]
Expected [a2], real [a2]
Expected [b1], real [b1]
Expected [b2], real [b2]
Expected [c1], real [b2]
Expected [c2], real [b2]

我平时只用string str = "",但我测试的时候就纳闷了

构造函数我觉得估计有问题

如何理解 std::string 的异常结果?

问题就出在这里

const char *c1 = std::string("c1").c_str();
const char *c2 = std::string("c2").c_str();

你在这里所做的是,在每一行中,你创建一个临时 std::string 对象,获取指向其内容的指针,并将该指针分配给一个变量。在每一行的末尾,临时 std::string 将被销毁,您通过 .c_str() 获得的指针将因此成为 dangling pointer...

一般来说,您的代码的两个版本都有 undefined behavior。这只是意味着:您编写的代码违反了允许编译器工作的基本假设(例如,如果您决定取消引用一个指针,该指针实际上指向一个有效的对象),因此,编译器不能期望以某种方式神奇地产生一个以有意义的方式运行的程序。为什么第一个版本 "works"(即似乎可以工作)而第二个版本与编译器碰巧将您的 C++ 代码翻译成什么机器代码无关的确切解释。通常,请注意,在第二个版本中,您的两个临时字符串是要构造的第一个字符串。一旦这些临时字符串被销毁,为它们分配的任何内存都可以重新用于之后创建的字符串。另一方面,在您的第一个示例中,您的临时字符串是最后构造的字符串。临时字符串被销毁后,将不会构造其他需要内存的本地对象。因此,您的两个指针将指向的内存内容不会被覆盖的可能性不大。因此,虽然您的指针不再是有效指针,并且不允许访问它们指向的对象(因为对象不再存在),但不管怎样,仍然可能会产生预期的结果。

由于您没有说明确切的编译器版本和使用的编译选项,因此很难准确说明您的编译器在做什么。但是让我们看看最新的 GCC 将如何处理优化级别 -O2(我无法仅使用默认设置重现该问题)。默认情况下,当前 GCC 版本使用的标准库执行上面代码的 short string optimization. Each of the strings in question is just two characters long. Thus, the internal buffer of the std::string objects and result of .c_str() will actually be located inside the std::string object on the stack. Looking at the assembly for the first and second 版本,我们看到编译器确实将临时字符串放入第一个版本中堆栈的两个不同位置,而将它们放在它后来在第二个版本中构造字符串 b2 的同一位置…