首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

C++ 陷阱:string 類臨時對象 c_str() 指針懸空問題

     編輯:C++ 入門

問題代碼


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; // 無輸出或亂碼
}

根因分析

  1. getString() 返回 臨時對象 (prvalue),生命週期僅持續到完整表達式結束 (分號處)
  2. .c_str() 返回指向該臨時對象內部緩衝區的指針
  3. 賦值給 pc 後,臨時對象立即銷毀,內部緩衝區被釋放
  4. pc 成為懸空指針,後續解引用導致未定義行為

兩種正確解決方案

方案一:延長臨時對象生命週期——綁定到具名變量


std::string str = getString(); // 拷貝/移動構造,生命週期延長至 str 作用域結束
const char* pc = str.c_str();  // 安全:str 仍然存活
std::cout << pc;

方案二:在單一表達式內完成使用


std::cout << getString().c_str(); // 完整表達式結束前臨時對象存活,安全

根據 C++ 標準,臨時對象在包含它的完整表達式結束前保持存活。

深度解析:C++17 複製消除 (RVO) 的影響

  • C++17 強制複製消除:std::string str = getString(); 直接在 str 存儲構造,無拷貝/移動
  • 但 getString().c_str() 中臨時對象仍在表達式結束時銷毀,規則未變
  • std::string_view (C++17) 同樣有此問題:string_view sv = getString(); 安全,getString().data() 危險

擴展:同類陷阱

代碼模式風險修正
vector f(); auto p = f().data();懸空指針auto v = f(); auto p = v.data();
unique_ptr f(); auto p = f().get();懸空指針,所有權轉移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++ 經典坑。
生命週期不匹配導致指針懸空。
修正口訣:要麼存變量,要麼一句話用完。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved