警告 C26446
偏好使用 gsl::at() 而不是未核取的下標運算子 (bounds.4)。
C++ 核心指導方針: Bounds.4:請勿使用未檢查 界限的標準程式庫函式和類型。
備註
C++ 核心指導方針的界限設定檔會嘗試消除記憶體的不安全操作。 它可協助您避免使用未經檢查的原始指標和未核取的作業。 執行對緩衝區的統一範圍檢查存取方式之一,就是使用 gsl::at()
來自指導方針支援程式庫的公用程式。 也適合依賴 STL 容器中可用的標準實作 at()
。
此規則有助於尋找透過呼叫 operator[]
執行可能未核取存取的位置。 在大部分情況下,您可以使用 來取代這類呼叫 gsl::at()
。
- 當下標運算子中使用非常數索引時,會標幟已知大小的陣列存取。 常數索引是由 C26483 STATIC_INDEX_OUT_OF_RANGE 處理。
- 在多載
operator[]
呼叫上發出警告的邏輯比較複雜:- 如果索引為非整數,則會忽略呼叫。 這也會處理標準對應中的索引,因為這類運算子中的參數會以傳址方式傳遞。
- 如果運算子標示為非擲回(使用
noexcept
、throw()
或__declspec(nothrow)
),則會標示呼叫。 我們假設如果下標運算子永遠不會擲回例外狀況,它就不會執行範圍檢查,或這些檢查是模糊不清的。 - 如果運算子未標示為非擲回,則如果運算子來自也會定義傳統
at()
成員函式的 STL 容器,則可能會標示它。 這類函式會透過簡單的名稱比對來偵測。 - 規則不會對標準
at()
函式的呼叫發出警告。 這些函式是安全的;以 取代它們gsl::at()
不會帶來太多價值。
- 索引到
std::basic_string_view<>
是不安全的,因此發出警告。 使用gsl::basic_string_span<>
取代標準,此標準string_view
一律會進行界限檢查。 - 實作不會考慮範圍檢查使用者程式碼在迴圈或分支中可能有某處。 在這裡,正確性會針對效能進行交易。 一般而言,您通常可以使用更可靠的反覆運算器或更精簡的增強
for
式 -迴圈來取代明確的範圍檢查。
範例
此範例示範函式如何 gsl::at
取代索引參考:
// C26446.cpp
#include <vector>
#include <gsl/gsl_util>
#include <iostream>
void fn()
{
std::vector<int> v{1, 2, 3, 4, 5};
// Normal bracket operators do not prevent you from accessing memory out of bounds.
std::cout << v[5] << '\n'; // C26446, prefer using gsl::at instead of using operator[].
// gsl::at prevents accessing memory out of bounds and invokes std::terminate on access.
std::cout << gsl::at(v, 5) << '\n';
}