2017-03-19 95 views
2

我有這樣的代碼(大約)在CPP的應用程序:爲什麼這會使用std ::的變換原因EXC_BAD_ACCESS

QList<Foo> rawAssets = getlist(); 
QVector<std::pair<QString, QString>> assets; 
std::transform(rawAssets.begin(), rawAssets.end(), assets.begin(), makePair); 

這導致exc_bad_access扔當我再次使用assets

但是,如果我將assets.begin()更改爲std::back_inserter(assets),那麼它按我的預期工作。

我發現了教程std::transform顯示這兩種用法。爲什麼我的情況是錯的?

回答

3

既然您剛宣佈QVector<std::pair<QString, QString>> assets;這是空的。因此assets.begin()等於assets.end(),並且指向空向量的末尾。

std::transform第三個參數是一個迭代,通過該transform的變換的結果(與每個寫後增加的話)。

當你通過assets.begin()時,transform會通過這個過去結束的迭代器寫入,導致超出邊界的寫入。這是大致相同,這樣做char x[3]; x[4] = 'a';

當您在std::back_inserter(assets)傳遞,您創建一個特殊的迭代器,使得通過它實際上插入書面元素寫入assets。所以一切都很好。

如果assets已經足夠大,並且您想要覆蓋中的元素,則可以使用第一種形式。第二種形式用於當你想擴展assets與轉換的結果。

+0

'assets.begin()因此等於assets.end()'這是我錯過的那篇文章。謝謝! – Daenyth

0

std::transform()假定它可以直接寫入輸出。你的情況是一個零大小的矢量。您可以通過將矢量顯式調整爲變換輸入的大小來修復該錯誤,或​​者使用已發現的back_inserter來修復該錯誤。

0

如果將assets的大小調整爲與transform之前的rawAssets相同的大小,則不會導致訪問不良。使用back_insert_iterator會導致push_back針對transform的每個迭代器被調用。如果沒有,它會嘗試訪問assets的第一個,第二個,第三個等元素,該元素仍然爲空,因此導致訪問錯誤。

1

assets作爲空向量開始。

transform()的第三個參數是輸出迭代器。您的代碼基本上等同於以下內容:

QVector<std::pair<QString, QString>> assets; 

auto output_iter=assets.begin(); 

// You now call transform(), passing output_iter 
// 
// transform() then essentially does the following: 

*output_iter++ = /* first transform()ed value */; 
*output_iter++ = /* second transform()ed value */; 

// ... and so on. 

這就是transform()的工作原理。由於assets()是一個空向量,因此begin()會爲您提供結束迭代器值,然後代碼繼續愉快地寫入向量末尾,然後廢棄自身。

你有兩個基本的選擇:

  1. 獲得begin()迭代器之前,resize()矢量到你即將transform()元素的數量,所以transform()最終填寫預先調整數組的內容,確切地說。但是,由於您的數據來自列表,因此不易獲得,因此:

  2. std::back_insert_iterator傳遞給transform(),而不是迭代器到空數組。

相關問題