const char* getString() {
return "just a test"; // 字符串字面量,靜態存儲期,安全
}
const char* pc = getString().c_str(); // 錯誤!若 getString 返回 std::string
std::cout << pc; // 未定義行為:輸出亂碼或崩潰
若 getString() 返回 std::string:
std::string getString() {
return "just a test"; // 返回臨時 string 對象
}
int main() {
const char* pc = getString().c_str(); // 危險!
std::cout << pc; // 無輸出或亂碼
}
getString() 返回 臨時對象 (prvalue),生命週期僅持續到完整表達式結束 (分號處).c_str() 返回指向該臨時對象內部緩衝區的指針pc 後,臨時對象立即銷毀,內部緩衝區被釋放pc 成為懸空指針,後續解引用導致未定義行為
std::string str = getString(); // 拷貝/移動構造,生命週期延長至 str 作用域結束
const char* pc = str.c_str(); // 安全:str 仍然存活
std::cout << pc;
std::cout << getString().c_str(); // 完整表達式結束前臨時對象存活,安全
根據 C++ 標準,臨時對象在包含它的完整表達式結束前保持存活。
std::string str = getString(); 直接在 str 存儲構造,無拷貝/移動getString().c_str() 中臨時對象仍在表達式結束時銷毀,規則未變std::string_view (C++17) 同樣有此問題:string_view sv = getString(); 安全,getString().data() 危險| 代碼模式 | 風險 | 修正 |
|---|---|---|
vector | 懸空指針 | auto v = f(); auto p = v.data(); |
unique_ptr | 懸空指針,所有權轉移 | auto p = f(); // 所有權轉移給 p |
mutex& getLock(); auto lk = std::unique_lock(getLock()); | 臨時 unique_lock 立即解鎖 | std::unique_lock lk(getLock()); |
☐ 任何返回「內部指針/引用/視圖」的成員函數(c_str()、data()、get()、operator[]),
其調用對象必須有足夠生命週期
☐ 臨時對象只能在同一完整表達式內安全使用其內部指針
☐ 需跨語句使用時,先綁定到具名變量(自動變量、成員變量、static 變量)
☐ 代碼審查時重點檢查「臨時對象.成員函數()」模式
「臨時對象.c_str()」是 C++ 經典坑。
生命週期不匹配導致指針懸空。
修正口訣:要麼存變量,要麼一句話用完。