2015-01-13 36 views
0

與deque在C++中有一個奇怪的問題。 假設我有一個大小爲4的雙精度浮點數。出於某種原因,在使用索引運算符時,我似乎能夠超出雙精度值的大小。問題與deques和超過deque大小與索引操作符

for(int i = 0; i < 7; i++) 
{ 
    x[i] = (double)(i*i); 
    cout << x[i] << endl; 
} 

其中x是雙端隊列: 換句話說,如果我寫了下面既沒有執行的編譯器和程序將BARF。而且我實際上能夠從中獲得輸出。 它不會增加雙端隊列的大小。如果我輸出x.size(),我仍然得到4. 什麼給? 我使用Code :: Blocks和它附帶的標準默認gcc編譯器。

+1

通過走出界限,您正在調用未定義的行爲,此時您的程序將被允許執行任何操作,包括擦除硬盤驅動器。 – sjdowling

+1

常規數組會發生同樣的情況。你爲什麼驚訝? –

+0

'既不是編譯器'編譯器如何知道只有4個項目? 「如果我寫下以下內容,執行中的程序也不會被禁止」我會問你 - 「執行會怎麼樣」是什麼意思?如果你不能回答這個問題,那麼你的非答案*就是答案。當你做這樣的事情時,沒有人知道該程序會做什麼。這就是你所說的「未定義的行爲」。 – PaulMcKenzie

回答

1

索引超出範圍會導致未定義的行爲,因此可能會發生任何事情。

許多容器會將當前的大小舍入到某個方便的值(例如2的冪),因此根據當前大小,在集合中的最後一個項目之後您將擁有一定量的內存。索引到該內存並嘗試讀取它會產生一些結果,但內存通常是未初始化的,所以結果通常是無意義的和無效的(儘管大多數不這樣做,容器可以執行邊界檢查並引發異常或者當你索引出界時幾乎任何其他的東西)。

IMO,at是一個相當差的工具來處理的可能性,但。一種更好的方式,以避免這樣的問題是基於範圍的for循環:

for (auto &d : x) { 
    d = d * d; 
    std::cout << d << "\n"; // avoid `endl`, which flushes the stream. 
} 

另一種可能性是使用標準算法:

還有一系列基於-
std::transform(x.begin(), x.end(), x.begin(), [](double d) { return d*d; }); 
std::copy(x.begin(), x.end(), std::ostream_iterator<double>(std::cout, "\n")); 

被算法(例如中,一組在升壓,至少一個或多個被建議用於將來的C++標準),即(做/將)允許的一般順序的東西:

copy(x, output_range<double>(std::cout, "\n")); 

由於該計算出上的x界限其由於缺少代碼範圍內的錯誤,因此幾乎不可能以這種方式意外索引出界限。

3

operator[]不會檢查,就像使用原始數組時一樣。該at成員函數呢,如果你改用

x.at(i); 

你會得到一個std::out_of_range異常,如果你超過deque的邊界。如果通過內存錯誤檢查程序(如valgrind)運行原始代碼,則會看到「無效讀取」和「無效寫入」錯誤。

如果你看cppreference's docs on operator[],你會看到註釋「沒有邊界檢查被執行」。

然而the docs for at()

如果不是容器,一個std例外的範圍內POS :: out_of_range拋出

走出界的容器上是不確定的行爲。如果您正在使用索引訪問索引,而您不確定它是否處於限制範圍內,則您的工作是檢查索引是否存在,或者使用at並可能處理異常。