c++ coredump例項解析
一、背景
經過重重除錯後,看到編譯成功的那一刻,內心充滿歡喜。當程式一執行,卻經常出現coredump的情況,此時內心是崩潰的。我想程式設計師經常會碰到這種情況,尤其使用c++語言編寫程式碼,由於沒有自動記憶體管理,經常會出現coredump情況,主要原因有以下幾類:
- 使用未賦值的指標
- 索引越界
- 格式化輸出時資料型別錯誤
- 併發引起的問題
下面對這幾類進行分析
二、場景分析及解決方案
場景一
struct A { char* str; }; class B { public: B() { str = NULL; val = -1;} B(const int& p_val); bool set(const int& value); bool get(const int& key, int& value); private: int val; }; int main() { A a; std::cout << "str = " << a.str << std::endl; B* aa = new B(); const int val = 615; aa.set(val); return 0; }
注:程式碼中set,get沒具體寫實現
問題描述:這段程式碼有兩處問題,第一處:使用未賦值的str會直接導致coredump,這段程式碼很簡單,一眼可以看出有問題,如果放在實際的工程專案中,其實很難發現;第二處:new指標物件後直接使用,如果記憶體分配失敗,也會出現問題。
解決方案:兩處地方都用到了指標,使用指標前都沒有判空,導致coredump,實際專案開發過程中,程式往往比較複雜,不像例項這樣直觀能看出問題,記住一點:使用指標前務必判空,不管是物件指標、簡單型別對應的指標、函式指標等等,另外分配堆記憶體後,記得一定要手動刪除,也可以使用物件池、記憶體池、智慧指標對指標物件進行自動管理,否則有可能撐爆記憶體,這塊不屬於本節內容,後續討論。
場景二
void test(const string& str, int idx) { std::cout << str[idx] << std::end; } int main() { int value[5] = {1, 2, 3, 4, 5}; std::cout << value[5] << std::end; std::map<int, int> p_map; std::map<int, int>::iterator iter = p_map.find(20); std::cout << "value = " << iter->second; return 0; }
問題描述:使用陣列資料時,沒有判斷索引的有效性;使用stl容器,迭代器沒有判斷end()直接用。
解決方案:使用陣列或容器時,務必根據陣列或容器的size檢查索引的有效性。
場景三
// 整型字串格式輸出
int value = 615;
printf("value[%s]\n", value);
// 字串字元形式賦值
char *str = 'dianjing';
printf("str[%s]\n", str);
問題描述:我們在輸出日誌,或進行格式化賦值時,會經常寫錯,整型資料使用字串輸出;另一種常見的錯誤是字串賦值時誤使用單引號進行賦值,編譯器會提示,但不會報錯,這樣即使使用try catch也catch不住這種coredump
解決方案:格式化輸出時,務必檢查資料型別和輸出格式的正確性,以及資料型別賦值的準確性。
場景四
問題描述:當主執行緒中使用並行執行緒進行並行執行時,並行執行緒中主執行緒local資料為空,不能用。
解決方案:並行執行緒回撥函式傳入主執行緒local資料,或建立併發資料,每個並行執行緒指向不同的併發資料
總結
程式出現coredump,千萬不要慌,希望通過本文能快速定位問題,後續會截圖具體coredump,對core檔案進行分析。
- 使用指標前一定要判空
- 使用容器時,務必檢查索引的有效性
- 格式化資料時,檢查資料型別和輸出格式的正確性
- 注意併發時,資料的有效性