背景
經過重重調試後,看到編譯成功的那一刻,內心充滿歡喜。當程序一運行,卻經常出現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);
問題描述:我們在輸出日誌,或進行格式化賦值時,會經常寫錯,整型數據使用字符串輸出,即使使用try catch也catch不住這種coredump
解決方案:格式化輸出時,務必檢查數據類型和輸出格式的正確性
場景四
問題描述:當主線程中使用並行線程進行並行執行時,並行線程中主線程local數據爲空,不能用。
解決方案:並行線程回調函數傳入主線程local數據,或創建併發數據,每個並行線程指向不同的併發數據
總結
程序出現coredump,千萬不要慌,希望通過本文能快速定位問題,後續會截圖具體coredump,對core文件進行分析。
- 使用指針前一定要判空
- 使用容器時,務必檢查索引的有效性
- 格式化數據時,檢查數據類型和輸出格式的正確性
- 注意併發時,數據的有效性