2014-02-27 39 views
10

默認情況下,std::stack的「基礎容器」是std::deque。因此,std::deque未定義的行爲對於std::stack是未定義的行爲。當描述成員函數的行爲時,其他站點「有效地」使用術語。我認爲這是爲了所有意圖和目的。因此,調用top()pop()相當於調用back()pop_back(),並且在空容器上調用這些屬性是未定義的行爲。爲什麼在STL中允許未定義的行爲?

從我的理解,它的未定義行爲的原因是爲了保持無丟包保證。我的推理是,operator[]對於std::vector有一個無丟包保證,如果容器大小大於N,它是未定義的行爲,但at()有很強的保證,如果n超出範圍則引發std::out_of_range

所以我的問題是,什麼是背後的一些事情有可能未定義的行爲和有沒有保證與強有力的保證,但拋出異常,而不是保證?

回答

14

當未定義行爲被允許時,出於效率的原因,它通常是

如果標準規定了當您訪問數組越界時必須發生的事情,那麼它會強制實施檢查索引是否在邊界內。矢量也是如此,它只是一個動態數組的包裝。

在其他情況下,允許未定義行爲以允許自由執行。但是,這也是關於效率的(因爲一些可能的實現策略在某些機器上可能比其他機器上的效率更高,並且C++會讓實施者選擇最有效的策略,如果他們願意的話。)

2

根據Herb Sutter一個明顯的原因是效率。他表示該標準對operator[]的異常規範沒有任何要求,或者是否需要進行綁定檢查。這取決於實施。

另一方面,vector<T>::operator[]()是允許的,但不是 要求,執行邊界檢查。這裏沒有措辭 標準的規範operator[]()的氣息,說什麼 關於邊界檢查,但也不是沒有,它 有異常規範,所以你的標準庫的實現 是自由地添加邊界檢查operator[]()任何要求也是。因此,如果您使用 operator[]()來請求不在向量中的元素,那麼您自己就是 ,並且標準不會保證 會發生什麼(儘管您的標準庫實現的文檔 可能) - 您的程序可能會立即崩潰,對 operator[]()的調用可能會拋出異常,或者看起來可能會發生 偶爾和/或神祕失敗。

鑑於邊界檢查保護我們免受許多常見問題的困擾,爲什麼operator[]()爲什麼不是operator[]()來執行邊界檢查? 簡短的答案是:效率。總是檢查邊界會導致所有程序都有 (可能很小)的性能開銷,即使是那些不會違反邊界的程序。 C++的精神包含了這樣一種說法,即由 和大的,你不應該支付你不使用的東西,因此operator[]()不需要邊界檢查 。在這種情況下,我們 還有一個額外的理由需要效率:向量旨在使用 而不是內置數組,因此應該與內置數組一樣有效,因爲內置數組不會進行邊界檢查。如果你想成爲 確保邊界被檢查,請改爲使用at()

如果你好奇的性能優勢,看到這兩個問題:

  1. ::std::vector::at() vs operator[] << surprising results!! 5 to 10 times slower/faster!
  2. vector::at vs. vector::operator[]

的共識似乎是,operator[]更有效(因爲std::vector只是一個動態數組的包裝,operator[]應該與您打電話時一樣高效它在一個數組上。)Herb Sutter似乎暗示它是否是異常安全的取決於編譯器供應商。