查看 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;
}
}