stringstream::str() 回傳**臨時 std::string 物件**,連續呼叫 .c_str() 會導致指向已銷毀物件的懸空指標。本文實測展示陷阱行為並提供安全替代模式。
std::stringstream ss("0123456789");
std::stringstream t_ss("abcdefghijklmnopqrstuvwxyz");
const char* cstr1 = std::string(ss.str()).c_str(); // 安全:延長臨時物件壽命
const char* cstr2 = ss.str().c_str(); // 危險:表達式結束銷毀
const char* cstr3 = ss.str().c_str(); // 危險:記憶體可能被覆寫
const char* cstr4 = ss.str().c_str(); // 危險
const char* t_cstr = t_ss.str().c_str(); // 危險
// 輸出結果(編譯器相關,展示未定義行為):
// cstr1: 0123456789
// cstr2: 0123456789 (偶然正確,記憶體未被覆寫)
// cstr3: abcdefghijklmnopqrstuvwxyz (被 t_ss 分配覆寫)
// cstr4: abcdefghijklmnopqrstuvwxyz
// t_cstr: abcdefghijklmnopqrstuvwxyz

ss.str() 回傳 **prvalue 臨時 std::string** 。.c_str() 回傳指向臨時物件內部緩衝區的指標。t_ss.str())可能重用相同記憶體位址,導致「神秘」內容變更。
// 印出指標位址
cstr2 addr: 0x10020134 // ss.str() 第一次
cstr3 addr: 0x10020014 // ss.str() 第二次(同 t_cstr!)
cstr4 addr: 0x10020014 // ss.str() 第三次
t_cstr addr: 0x10020014 // t_ss.str() 復用相同位址
證明:臨時物件記憶體被後續分配覆寫,指標指向新內容。
std::string str = ss.str(); // 命名物件,壽命至作用域結束
const char* cstr = str.c_str(); // 安全:str 仍存活
// 使用 cstr...
const std::string& ref = ss.str(); // const 左值參考綁定 → 延長至 ref 作用域結束
const char* cstr = ref.c_str(); // 安全
// 使用 cstr...
標準規定:const T& ref = temporary; 會將臨時物件壽命延長至參考變數壽命結束。
// 直接傳遞 string 給接受 const string& 的函式
void process(const std::string& s);
process(ss.str()); // 臨時物件綁定到 const 參考,安全
// 或使用 C++17 string_view(零複製)
void process_v(std::string_view sv);
process_v(ss.str()); // 隱性轉換,安全
此陷阱**不限於 stringstream**,所有回傳類別值(非參考)的函式均適用:
std::string get_name();
const char* p = get_name().c_str(); // 錯誤!
// 正確
std::string name = get_name();
const char* p = name.c_str();
-Wdangling-pointer (C++20 起) 部分偵測。scan-build 可偵測「使用已釋放記憶體」。--enable=warning 偵測「指標指向臨時物件」。.str().c_str()、.c_str() 等鏈式呼叫結果存儲指標。std::string 到命名變數或 const 參考**。const std::string& 或 std::string_view,避免 const char* 傳遞。