C++ 中的 std::vector 為什麼可以越界訪問?
如題,代碼如下:
#include &
#include &
#include &
#include &
using std::vector;
using std::string;
using std::cout;
using std::cin;
using std::endl;
int main(int argc, const char * argv[]) {
//聲明了一個大小為5的vector
vector&
ivec(5); //這裡輸出是5
cout&<&<"The size is: "&<&
//這裡輸出也是0
cout&<&
//這裡輸出還是0,為什麼?這不是應該超出邊界了?
cout&<&
return 0;
}
如題,如何解釋上面的問題?
我用的Xcode最新版本運行的。
operator[]是不檢查的,你得用at函數
問題:為什麼我可以亂穿馬路?解釋:亂穿馬路違法,但是一般沒人會來管你。沒撞死算幸運,撞死活該。
ivec[10000]肯定是越界了,可以改一些編譯參數(比如優化全開)應該會輸出其他隨機值。
capacity() 查當前容量,size() 獲取已有元素個數
我記得vector的實現里,容量是0.1.2.4.8.16.32...這樣增加的
我想這可能跟vector的內存預分配機制有關係
引用:因此STL實現者在對vector進行內存分配時,其實際分配的容量要比當前所需的空間多一些。就是說,vector容器預留了一些額外的存儲區,用於存放新添加的元素,這樣就不必為每個新元素重新分配整個容器的內存空間。具體到你的問題
vector& reference operator[](size_type _Pos)
{ // subscript mutable sequence
#if _ITERATOR_DEBUG_LEVEL == 2
if (size() &<= _Pos)
{ // report error
_DEBUG_ERROR("vector subscript out of range");
_SCL_SECURE_OUT_OF_RANGE;
}
#elif _ITERATOR_DEBUG_LEVEL == 1
_SCL_SECURE_VALIDATE_RANGE(_Pos &< size());
#endif /* _ITERATOR_DEBUG_LEVEL */
return (*(this-&>_Myfirst + _Pos));
}
這是 VS2013 里的 operator[],可以看出,對越界的檢測
if (size() &<= _Pos)只會在 Debug 模式下進行,而且是可以通過
#define _HAS_ITERATOR_DEBUGGING 0屏蔽掉這個檢測的。而在 Release 模式下,根本不會進行這種檢測。vector內部實現中有3個指針:T *first, *finish, *end_of_storage;first指向動態內存的初始位置,end_of_storage指向動態內存的末尾的下一下元素,finish初始化時與first指向同一位置,之後每加入一個元素(一個push_back操作),finish++.方法vector::size()返回 (size_type)finish-first.方法vector::capcity()返回(size_type)end_of_storage-first.方法vector::operater[](size_t)不進行邊界檢查,如果需要邊界檢查用at().
如果你知道vector啊數組之類的還可以接受負數下標(只不過會運行出錯)會更驚訝的,這就是為什麼c++的vector模板類和array模板類都提供了看上去很沒用的at方法,就是為了防止out of bound access
我用clang++和Xcode試了一下,size返回是5。使用[]訪問越界值是未定義行為,所以會發生什麼誰也說不清。
你size返回0,看看是不是哪寫錯了。http://www.cplusplus.com/reference/vector/vector/operator[]/Portable programs should never call this function with an argument n that is out of range, since this causes undefined behavior.
如果你能確保程序不會越界訪問,C++VECTOR允許你繞過邊界檢查(下標訪問 [])。這樣可以提高性能。
如果你不能確信程序是否能做到不越界,C++VECTOR提供邊界檢查(at函數),接下來你還需要處理越界的異常。
推薦閱讀:
※以後的C++編譯器有沒有可能使用C#來編寫?
※編譯器或解釋器前端對於作用域的處理方法?
※GitHub 上有沒有什麼簡單精緻的編譯器源碼適合初學者研讀??
※為什麼大部分傑出的程序員都在內心傾向於研究操作系統和編譯器?
※GNU GCC使用ld鏈接器進行鏈接的完整過程是怎樣的?