今天解决一个线上Bug时,遇到一个string::c_str()
引起的崩溃问题。
写了一个最小Demo,大概长这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include <iostream> #include <string> std::string foo() { return std::string("foo"); } std::string bar0() { return std::string(foo().c_str()); } std::string bar1() { const char * tmp = foo().c_str(); return std::string(tmp); } std::string bar2() { std::string foo_copy = foo(); const char * tmp = foo_copy.c_str(); return std::string(tmp); } int main() { std::cout << "bar0(): " << bar0() << std::endl; std::cout << "bar1(): " << bar1() << std::endl; std::cout << "bar2(): " << bar2() << std::endl; }
|
这是在我的开发环境的输出结果:
1 2 3
| bar0(): foo bar1(): bar2(): foo
|
可以看到,上面bar1的写法会得到预期之外的结果。这是为什么呢?
- 函数bar1()的返回值是临时变量
- 在调用完bar1()后,它的返回值会立即被释放
- 释放后,tmp就变成一个野指针了
为什么bar0是正常的?
- foo()返回的临时变量的生命周期是在分号之前,它是有效的
为什么bar2是正常的?
- foo()返回的临时变量已赋值拷贝给foo_copy了
- foo_copy的生命周期则是在bar2结束前
因此,当我们要对函数返回的string值进行c_str()调用时,要注意返回的string的生命周期。如果需要,我们可以赋值拷贝给另外的变量,来延长它的生命周期。
1 2
| std::string str_copy = foo(); const char *tmp = str_copy.c_str();
|
Reference