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& ivec(5);

這裡指定了vector只有初始化的5個元素,但他實際上可能分配了5000個元素所需要的空間

所以,你這裡直接訪問輸出ivec[1000]是不會出錯的

訪問vector,at()更安全一些

如果越界的訪問地址超出了預分配的空間,那就是相當於訪問了一個未被其他程序佔用的內存,同樣不會出錯,但不確定,如果被佔用,同樣會出錯

更多 關注

你好,C++ - 知乎專欄


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鏈接器進行鏈接的完整過程是怎樣的?

TAG:程序員 | C | 數據結構 | 編譯器 |