使用是否安全(str1 + str2).c_str()?

时间:2013-08-09 12:06:14

标签: c++ string

我已经测试了这段代码:

#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 个答案:

答案 0 :(得分:57)

在你的例子中,这不安全。但是在

中是安全的
printf("%s\n", (a + b).c_str());

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

“未定义行为”中最糟糕的部分是事情可能显然仍然有效......(只有当你在包括你父母在内的广大受众面前制作你的演示时,UB代码才会崩溃;-))

答案 1 :(得分: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() );

它会起作用,因为对象还没有被破坏(请记住,分号后......)。

答案 2 :(得分:5)

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

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

//other operations with s3

答案 3 :(得分:4)

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