Aviso C26446
Prefira usar gsl::at() em vez do operador subscrito não verificado (bounds.4).
Diretrizes Principais do C++: Bounds.4: Não use funções da biblioteca padrão nem tipos que não tem limites verificados.
Comentários
O perfil Bounds das Diretrizes principais do C++ tenta eliminar manipulações não seguras de memória. Ele ajuda a evitar o uso de ponteiros brutos e operações não verificadas. Uma forma de executar o acesso uniforme verificado por intervalo aos buffers é usar o utilitário gsl::at()
na Biblioteca de Suporte de Diretrizes. Também é uma boa prática confiar em implementações padrão de at()
disponíveis em contêineres da STL.
Essa regra ajuda a encontrar locais em que o acesso potencialmente não verificado é executado por meio de chamadas para operator[]
. Na maioria dos casos, você pode substituir essas chamadas usando gsl::at()
.
- O acesso a matrizes de tamanho conhecido é sinalizado quando um índice não constante é usado em um operador de índice. Os índices de constantes são tratados pelo STATIC_INDEX_OUT_OF_RANGE C26483.
- A lógica para avisar em chamadas sobrecarregadas
operator[]
é mais complexa:- Se o índice não for integral, a chamada será ignorada. Isso também lida com a indexação em mapas padrão, uma vez que os parâmetros nesses operadores são passados por referência.
- Se o operador for marcado como não emissor (usando
noexcept
,throw()
ou__declspec(nothrow)
), a chamada será sinalizada. Supomos que, se o operador subscrito nunca lançar exceções, ele não executará verificações de intervalo ou essas verificações serão obscuras. - Se o operador não estiver marcado como não emissor, ele poderá ser sinalizado se for proveniente de um contêiner da STL que também define uma função de membro convencional
at()
. Essas funções são detectadas pela simples correspondência de nomes. - A regra não avisa em chamadas para funções padrão
at()
. Essas funções são seguras; substituí-las porgsl::at()
não agregaria muito valor.
- A indexação em
std::basic_string_view<>
não é segura, portanto, um aviso é emitido. Substitua ostring_view
padrão usandogsl::basic_string_span<>
, que é sempre marcado por limites. - A implementação não considera verificações de intervalo que o código do usuário pode ter em algum lugar em loops ou ramificações. Aqui, a precisão é trocada pelo desempenho. Em geral, geralmente você pode substituir verificações explícitas de intervalo usando iteradores mais confiáveis ou loops avançados
for
mais concisos.
Exemplo
Este exemplo demonstra como a função gsl::at
pode substituir uma referência indexada:
// 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';
}