2013-10-12 30 views
2

我讀三個大的二進制文件(每個c.180Mb)到一個std ::向量如下時:壞分配錯誤填充的std ::矢量

m_ifStream.open("myfile.dat", std::ios::binary | std::ios::in); 

if (m_ifStream) 
{ 
    //Obtain input stream length 
    m_ifStream.seekg (0, ios::end); 
    streamLength = (size_t)(m_ifStream.tellg()); 
    m_ifStream.seekg (0, ios::beg); 

    //Reserve doesn't work around the problem, may be more efficient though... 
    //m_buffer = new vector<unsigned char>(); 
    //m_buffer->reserve(streamLength); 

    //Next line sometimes results in bad_alloc when reading a large file 
    m_buffer = new vector<unsigned char>((std::istreambuf_iterator<char>(m_ifStream)), (std::istreambuf_iterator<char>())); 
} 

的調用來填充矢量失敗,拋出「不良分配」異常。

閱讀第一個文件時,羣體有時會失敗;有時在第二或第三次失敗。我正在使用Visual Studio 2010並將我的代碼編譯爲32位,它應該能夠處理高達2Gb的代碼。我使用的是16Gb RAM的機器,至少10Gb空閒,所以缺少可用內存不是問題。調試和發佈配置中都會出現該錯誤。

預分配內存reserve沒有幫助。

該向量的max_size屬性返回2^32,所以它看起來不是容器中的限制。

代碼很好,大小合併大小大於180Mb的小文件,使我認爲我的代碼正在碰到邊界。

是否有一種可接受的方式來從大型輸入文件填充矢量?我想避免遍歷文件中的每個字節,並認爲使用istreambuf_iterator將針對這種操作進行優化。

+0

是的,它是一個矢量。 – pdm2011

回答

1

您正在做更多的工作並分配比您需要的更多的內存。

首先拆下指針,它沒有帶來任何

vector<char> m_buffer; 

然後調用調整(不保留),以正確的大小

m_buffer.resize(streamLength); 

如果你要運行的內存,這是當它會發生。

最後直接讀取數據到載體,不使用streambuf_iterator,它不知道誰在幕後有什麼

m_ifStream.read(&m_buffer[0], streamLength); 

這裏的主要好處是,你只分配一個向量(你的代碼有兩個向量之一被複制在另一個之上),其次你已經刪除了所有的絨毛,並且只剩下兩個基本操作,分配內存,讀取文件。

+0

應該調整大小一般比儲備偏愛嗎? – pdm2011

+0

@ pdm2011不,因爲他們做了不同的事情。保留分配內存但不調整矢量大小,resize調整矢量大小(這顯然意味着分配內存)。在你的代碼中,矢量被以下操作隱式調整大小:在我的代碼中,我需要明確調整矢量的大小,因爲我直接讀取矢量,所以它必須在正確的大小之前完成。 – john

+0

感謝您的回覆。我用你的建議,但不幸的是,同樣的問題發生,這次在第四次調用調整大小。我的懷疑是在代碼中的其他地方發生堆損壞,但我沒有發現任何事情,並且代碼對於大量較小的文件是健壯的。我正在使用生成的包裝器在C#和非託管代碼之間進行編組,這可能會進行一些過度的容器複製 - 我會嘗試通過探查器運行它,並查看64位版本的效果。 – pdm2011

0
m_buffer = new vector<unsigned char>(); 
m_buffer->reserve(streamLength); 

//Next line sometimes results in bad_alloc when reading a large file 
*m_buffer = vector<unsigned char>((std::istreambuf_iterator<char>(m_ifStream)), (std::istreambuf_iterator<char>())); 

令我驚訝的第一件事是將要覆蓋一個vector的已預分配區域。如果你創建一個新的向量來覆蓋那個向量,那麼在做「保留」時顯然沒有意義。這只是意味着你必須有空間來存放這些相對較大的向量。

我會通過改變m_buffer不爲指針,以矢量開始 - 這樣,你不必叫new vector<unsigned char> - 它提供很少的目的有一個指向向量充其量,爲您節省約16字節,如果你的矢量不包含任何東西]。

然後刪除reserve。看看這是怎麼回事。

+0

這實際上是我最初做的 - 我介紹了儲備,因爲我已經讀過它可能有幫助。我編輯了這個問題來反映這一點。 – pdm2011

2

如果你想有您的來電reserve()對實際讀取任何影響,你應該創建一個臨時std::vector<unsigned char>並分配這個臨時的目標向量。相反,you`使用類似

m_buffer->assign(std::istreambuf_iterator<char>(m_ifStream), 
       std::istreambuf_iterator<char>()); 

讀取該文件,而不保留在某些方面可能會破壞你的記憶,但我不希望該程序運行的內存對於像你這樣的小文件(文件一對夫婦幾GB可以被認爲是大的; 160MB並不是很大)。如果您知道文件的大小,你可能是最好的時候使用read()成員讀取文件,但:

m_buffer->resize(streamLength); 
m_ifStream.read(reinterpret_cast<char*>(m_buffer->data()), streamLength); 

我個人的猜測是std::bad_alloc例外實際上是從一個錯誤的決定文件的大小產生。例如,我不認爲std::size_t必須大到足以容納std::streamsize。另外,沒有嘗試驗證這些操作中的任何操作是否成功,並且如果流無法打開,seekg()將返回pos_type(-1),這將轉化爲相當大的std::size_t