查看 Visual Studio 2013的stl vector代碼, 發現push_back要先判斷元素是否本來就在vector裏面,再分情況push_back.
粗看不解,以爲多此一舉,其實裏面暗藏玄機。
所以就搜索一下,發現了這個問題“Is it safe to push_back an element from the same vector?”的討論,https://stackoverflow.com/questions/18788780/is-it-safe-to-push-back-an-element-from-the-same-vector
原來push_back的實現不但沒問題,而且還是修復了可能的bug。就連stl標準委員會的人都曾犯過這種錯誤。
http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#526
原因是push_back的時候可能會由於size()==capacity() 導致vector的地址重新分配,這樣指向原vector數據的指針就是無效指針,再訪問這個無效指針就會出問題。
看如下代碼:
vector<int> v;
v.push_bac(1);
v.push_back(v[0]); //在重新分配內存後,v[0]的地址會發生改變,如果還訪問就的v[0]就是非法訪問了。
同理insert等操作也需要先判斷元素地址是否本來就在vector裏面。
附VS2013 STL ,vector的push_back 實現代碼:
void push_back(const value_type& _Val)
{ // insert element at end
if (_Inside(_STD addressof(_Val)))
{ // push back an element
size_type _Idx = _STD addressof(_Val) - this->_Myfirst;
if (this->_Mylast == this->_Myend)
_Reserve(1);
_Orphan_range(this->_Mylast, this->_Mylast);
this->_Getal().construct(this->_Mylast,
this->_Myfirst[_Idx]);
++this->_Mylast;
}
else
{ // push back a non-element
if (this->_Mylast == this->_Myend)
_Reserve(1);
_Orphan_range(this->_Mylast, this->_Mylast);
this->_Getal().construct(this->_Mylast,
_Val);
++this->_Mylast;
}
}