![](/img/trans.png)
[英]Why does a memory leak occur in this code when a bad_alloc exception is thrown for T2
[英]Why bad_alloc() exception thrown in case of size_t
我正在處理下面的代碼,當我執行此代碼時,我得到一個std::bad_alloc
異常:
int _tmain(int argc, _TCHAR* argv[])
{
FILE * pFile;
size_t state;
pFile = fopen("C:\\shared.tmp", "rb");
if (pFile != NULL)
{
size_t rt = fread(&state, sizeof(int), 1, pFile);
char *string = NULL;
string= new char[state + 1];
fclose(pFile);
}
return 0;
}
這下面的行導致拋出異常:
string = new char[state + 1];
為什么會這樣,我該如何解決這個問題呢?
您正在傳遞未初始化的64位(現代64位系統上的8個字節)變量, state
,並告訴fread
讀取sizeof(int)
(32位,同一系統上的4個字節)字節將文件存入此變量。
這將覆蓋讀取值的變量的4個字節,但保留其他4個未初始化的。 它覆蓋的4個字節取決於體系結構(在Intel CPU上最不重要,在big-endian配置的ARM上最重要),但結果很可能是垃圾,因為4個字節未初始化並且可能包含任何內容。
在您的情況下,很可能它們是最重要的字節,並且至少包含一個非零位,這意味着您嘗試分配遠遠超過4GB的內存,這是您沒有的。
解決方案是使state
為std::uint32_t
(因為你顯然希望文件包含4個字節代表無符號整數;不要忘記包含<cstdint>
)並傳遞sizeof(std::uint32_t)
,一般情況下確保對於傳遞指針和大小的每個fread
和類似的調用,確保指針指向的東西實際上具有您傳遞的大小。 傳遞size_t*
和sizeof(int)
不能滿足64位系統的這些要求,並且由於無法保證C ++基本類型的大小,因此通常不希望將它們用於二進制I / O.
你可以在C ++代碼中改進各種各樣的東西,但是有很多原因,為什么你最終會遇到這種行為:
首先,變量state
的類型為size_t
,但是您的代碼嘗試使用fread(&state, sizeof(int), 1, pFile);
初始化其值fread(&state, sizeof(int), 1, pFile);
。 現在,如果sizeof(state) != sizeof(int)
那么你有未定義的行為。 如果sizeof(state) < sizeof(int)
,那么fread
語句通常會在存儲變量state
后覆蓋一些任意內存。 這會導致未定義的行為(例如, state
可能具有一些隨機大值,並且分配失敗)。
其次,如果sizeof(state) > sizeof(int)
,則state
僅被部分初始化,其實際值取決於初始化(通過fread
)和未初始化的位。 因此它的值可能很大,分配可能會失敗。
第三,如果sizeof(state) == sizeof(int)
則可能是讀取的值太大,並且分配因為內存不足而失敗。
第四,從文件中讀取的值可能具有一些不同的編碼或字節順序。 例如,如果值寫入到big-endian格式的文件,但fread
一個little-endian的CPU上,可能會導致字節被錯誤地交換。 在使用read值之前,您可能需要交換字節。
我建議你改為使用<cstdint>
(或<stdint.h>
for pre-C ++ 11)中的一些固定寬度整數類型,例如std::uint64_t
用於變量state
,使用fread(&state, sizeof(state), 1, pFile);
讀取值fread(&state, sizeof(state), 1, pFile);
如果CPU的字節順序與存儲在文件中的值的字節順序不匹配,則為字節交換state
。
您應該決定您願意分配的最大字符數是多少,如果state
大於該值,則應該輸出錯誤。 幾乎可以肯定,它是。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.