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 por gsl::at() não agregaria muito valor.
  • A indexação em std::basic_string_view<> não é segura, portanto, um aviso é emitido. Substitua o string_view padrão usando gsl::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';
}