两个不同const char*指针值相同,疑为C++未定义行为求解
临时std::string对象调用c_str()导致的未定义行为解析
你遇到的确实是未定义行为,具体场景如下:
使用g++ 4.4.7编译执行以下代码时:
#include <iostream> #include <string> using namespace std; int main() { string A = "-A"; string B = "_B"; string common = "Common"; const char* commonA = (common + A).c_str(); const char* commonB = (common + B).c_str(); cout << commonA << endl; cout << commonB << endl; return 0; }
输出结果中commonA和commonB均为"Common_B";但将代码放入在线C++ IDE执行时,能得到预期结果:commonA为"Common-A",commonB为"Common_B"。而将字符串拼接与c_str()调用拆分为两步后,g++ 4.4.7也能得到预期结果:
string commonA_str = common + A; string commonB_str = common + B; const char* commonA = commonA_str.c_str(); const char* commonB = commonB_str.c_str();
原因分析
核心问题在于临时std::string对象的生命周期:
(common + A)会生成一个临时std::string对象,这个对象的生命周期仅持续到当前完整表达式结束(即该行代码的分号处)。表达式结束后,临时对象被销毁,其内部管理的字符数组内存也会被释放。- 此时
commonA保存的是指向已销毁内存的野指针,后续对该指针的访问属于未定义行为——编译器可自由处理这种情况,没有固定结果。 - g++ 4.4.7的实现中,可能为两个临时对象分配了同一块内存空间,第二个临时对象
(common + B)覆盖了第一个临时对象的内存区域,导致两个指针最终都指向第二个字符串的内容。在线IDE使用的编译器可能采用了不同的内存分配策略,恰好表现出预期结果,但这只是巧合,不能依赖这种行为。
安全的实现方式
要保证c_str()返回的指针有效,必须让生成的字符串对象的生命周期覆盖指针的使用周期:
- 将拼接后的结果保存到具名的std::string变量中,具名变量的生命周期会持续到其所在作用域结束,只要变量未被销毁,
c_str()返回的指针就始终有效。
示例代码:#include <iostream> #include <string> using namespace std; int main() { string A = "-A"; string B = "_B"; string common = "Common"; // 先将拼接结果保存到具名变量 string commonA_str = common + A; string commonB_str = common + B; // 再获取c_str()指针 const char* commonA = commonA_str.c_str(); const char* commonB = commonB_str.c_str(); cout << commonA << endl; cout << commonB << endl; return 0; } - 如果不需要保存拼接后的字符串,也可以直接在同一个表达式中使用拼接结果,避免保存指针:
这种方式下,临时对象的生命周期会持续到输出操作完成,不会出现野指针问题。cout << common + A << endl; cout << common + B << endl;
内容的提问来源于stack exchange,提问作者MrMiserMeister
相关产品推荐
相关产品推荐

