36

我已经测试了这段代码:

#include <iostream>
#include <cstdio>
#include <string>
using namespace std;

int main()
{
    string s1("a"),s2("b");
    const char * s = (s1+s2).c_str();
    printf("%s\n",s);
}

它返回“ab”。

据我所知,因为(s1 +s2)是一个临时对象并且可能会以某种方式消失(我不知道),所以const char * s可能指向未定义的内存并可能被转储。

那么使用这样的东西安全.c_str()吗?

4

4 回答 4

57

在您的示例中不安全。它是安全的,但在

printf("%s\n", (a + b).c_str());

原因是临时值(如 的结果a + b)在完整表达式的末尾被破坏。在您的示例中,const char *包含临时的完整表达式仍然存在,并且取消引用它是未定义的行为。

“未定义的行为”最糟糕的部分是事情可能无论如何都可以正常工作......(只有当你在包括你父母在内的广大观众面前制作演示时,UB代码才会崩溃;-))

于 2013-08-09T12:07:44.767 回答
29

在那个例子中,我们可以引用标准:

12.2 临时对象 [class.temporary]

临时对象被销毁作为评估完整表达式(1.9)的最后一步,该完整表达式(在词法上)包含它们被创建的点。即使评估以抛出异常结束也是如此。销毁临时对象的值计算和副作用仅与完整表达式相关联,与任何特定子表达式无关。

那是在您的行的分号之后:

const char * s = (s1+s2).c_str(); // <- Here

所以在这里:

printf("%s\n",s); // This line will now cause undefined behaviour.

为什么?因为当你的对象被破坏时,你现在不知道这个地方是什么了......

这里的坏事是,对于未定义的行为,您的程序可能似乎在第一次工作,但是......它肯定会在最坏的时候崩溃......

你可以做:

printf( "%s\n", (s1+s2).c_str() );

它将起作用,因为该对象尚未被破坏(请记住,在分号之后......)。

于 2013-08-09T12:16:57.230 回答
5

它不安全,但是您可以轻松地分配给新变量,并且指针在该变量的范围内将是安全的:

string s1("a"), s2("b") , s3;
s3 = s1 + s2;
printf("%s\n", s3.c_str());

//other operations with s3
于 2013-08-09T12:17:15.157 回答
4

像大多数编程结构一样,如果你正确使用它是“安全的”,如果你马虎,它就不是“安全”的。在这种情况下,正确使用它意味着注意对象的生命周期。运算符创建一个临时对象,该+对象在语句结束时被销毁,并且在const char*创建它的语句之后返回不再有效。因此,您可以将结果c_str()直接传递给函数,但不能保存指针以供以后使用。

于 2013-08-09T12:26:31.347 回答