警告 C26446
unチェック 添字演算子 (bounds.4) の代わりに gsl::at() を使用します。
C++ Core Guidelines: Bounds.4: Don't use standard-library functions and types that are not bounds-checked (境界がチェックされていない標準ライブラリの関数と型を使用しない)。
解説
C++ Core Guidelines の Bounds プロファイルは、メモリの安全ではない操作の排除を試みます。 生ポインターと未チェックの演算を使用を回避するのに役立ちます。 バッファーへの一貫した範囲確認済みアクセスを実行する 1 つの方法は、Guidelines Support Library の 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<>
へのインデックス付けは安全ではないため、警告が出されます。 標準のstring_view
を、必ず境界がチェックされるgsl::basic_string_span<>
を使用して置き換えてください。- 実装では、ユーザー コードがループまたは分岐内のどこかにある可能性がある範囲チェックは考慮されません。 ここでは、精度はパフォーマンスと交換されます。 一般に、明示的な範囲チェックはより信頼性の高い反復子またはより簡潔な強化された
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';
}