今天在寫代碼的時候突然遇到一箇中斷問題,但是光看代碼根本發現不了錯誤,代碼大概類似於:
typedef struct MemsetTest
{
int year;
map<int,string> m_map;
MemsetTest()
{
memset(this , 0 , sizeof(MemsetTest));
}
}MemsetTest;
int Main()
{
MemsetTest tTest;
tTest.year = 2020;
tTest.m_map[5] = "5";
}
其中爲map添加值那一行會報錯。
遇到這個問題之後看代碼是在想不出問題在哪,然後我就把源代碼中MemsetTest的結構體給複製到了一個新的工程中測試,但是還是會爆錯,於是我試着刪除了MemsetTest的m_map變量,在測試是可以正常運行的;但是變得更迷惑了,map用了沒有一千也有八百次了,爲什麼這裏會死機?就繼續刪代碼一點點測試,最後刪到發現有memset與map同時存在就會出問題;在網上一搜索瞭解到問題果然出現在memset上:memset()函數將對象的所有內存都初始化爲0,這在初始化的類是一個POD類型(Plain Old Data)時是沒有問題的,因爲POD類型的二進制內容可以隨便複製、移動、重置而不會改變POD類型對象的值。ConfigSettings成員都是POD類型(int,char,float…),而且ConfigSettings類既不存在虛繼承也不存在虛函數,所以可以對ConfigSettings使用memset()函數進行初始化。但是因爲我在MemsetTest中加入了map類型的成員變量,就導致MemsetTest不再是一個POD類型結構,所以當使用memset()函數進行初始化時會對對象造成破壞,map底層是紅黑樹,其中必然包括各種指針,當使用memeset將對象所有內存初始化爲0的時候,map中的各種指針必然就變成了null_ptr,整個結構已經被完全破壞了,所以會後面對map進行操作的時候就會出現崩潰。
最後解決辦法
- 重新寫MemsetTest的構造函數,不再使用memset()函數初始化對象。
- 將成員變量map設置爲static類型,可以避免在memset()時被破壞.
另外以後一定要注意構造函數初始化儘量不要直接使用memset,因爲就算你寫的時候是一個POD結構,但隨着時間的流逝後續其他人維護就可能添加指針等,到時他如果不瞭解這個問題就又會困住他好久。