Partilhar via


Checked Iterators

Os iteradores verificados garantem que os limites do contêiner não sejam substituídos. Os iteradores verificados aplicam-se às compilações de versão e às compilações de depuração. Para obter mais informações sobre como usar iteradores de depuração quando você compila no modo de depuração, consulte Debug Iterator Support.

Remarks

Para obter informações sobre como desativar avisos gerados por iteradores verificados, consulte _SCL_SECURE_NO_WARNINGS.

Você pode usar a macro do _ITERATOR_DEBUG_LEVEL pré-processador para habilitar ou desabilitar o recurso de iteradores verificados. Se _ITERATOR_DEBUG_LEVEL for definido como 1 ou 2, o uso não seguro de iteradores causa um erro de tempo de execução e o programa é encerrado. Se definido como 0, os iteradores verificados serão desativados. Por padrão, o valor para _ITERATOR_DEBUG_LEVEL é 0 para compilações de versão e 2 para compilações de depuração.

Important

A documentação mais antiga e o _SECURE_SCL código-fonte podem referir-se à macro. Use _ITERATOR_DEBUG_LEVEL para controlar _SECURE_SCL. Para obter mais informações, consulte _ITERATOR_DEBUG_LEVEL.

Quando _ITERATOR_DEBUG_LEVEL é definido como 1 ou 2, estas verificações de iterador são executadas:

  • Todos os iteradores padrão (por exemplo, vector::iterator) são verificados.

  • Se um iterador de saída for um iterador verificado, chamará para funções de biblioteca padrão, como std::copy obter comportamento verificado.

  • Se um iterador de saída for um iterador não verificado, as chamadas para funções de biblioteca padrão causarão avisos do compilador.

  • As seguintes funções geram um erro de tempo de execução se houver um acesso fora dos limites do contêiner:

Quando _ITERATOR_DEBUG_LEVEL é definido como 0:

  • Todos os iteradores padrão são desmarcados. Os iteradores podem ir além dos limites do contêiner, o que leva a um comportamento indefinido.

  • Se um iterador de saída for um iterador verificado, chamará para funções de biblioteca padrão, como std::copy obter comportamento verificado.

  • Se um iterador de saída for um iterador não verificado, as chamadas para funções de biblioteca padrão terão um comportamento não verificado.

Um iterador verificado refere-se a um iterador que chama invalid_parameter_handler se você tentar ultrapassar os limites do contêiner. Para obter mais informações sobre invalid_parameter_handlero , consulte Validação de parâmetros.

Os adaptadores iteradores que suportam iteradores verificados são checked_array_iterator Class e unchecked_array_iterator Class.

Examples

Quando você compila usando _ITERATOR_DEBUG_LEVEL definido como 1 ou 2, ocorrerá um erro de tempo de execução se você tentar acessar um elemento que está fora dos limites do contêiner usando o operador de indexação de determinadas classes.

// checked_iterators_1.cpp
// cl.exe /Zi /MDd /EHsc /W4

#define _ITERATOR_DEBUG_LEVEL 1

#include <vector>
#include <iostream>

using namespace std;

int main()
{
    vector<int> v;
    v.push_back(67);

    int i = v[0];
    cout << i << endl;

    i = v[1]; //triggers invalid parameter handler
}

Este programa imprime "67", em seguida, aparece uma caixa de diálogo de falha de asserção com informações adicionais sobre a falha.

Da mesma forma, quando você compila usando _ITERATOR_DEBUG_LEVEL definido como 1 ou 2, ocorrerá um erro de tempo de execução se você tentar acessar um elemento usando front ou back em classes de contêiner quando o contêiner estiver vazio.

// checked_iterators_2.cpp
// cl.exe /Zi /MDd /EHsc /W4
#define _ITERATOR_DEBUG_LEVEL 1

#include <vector>
#include <iostream>

using namespace std;

int main()
{
    vector<int> v;

    int& i = v.front(); // triggers invalid parameter handler
}

Este programa exibe uma caixa de diálogo de falha de asserção com informações adicionais sobre a falha.

O código a seguir demonstra vários cenários de caso de uso do iterador com comentários sobre cada um. Por padrão, _ITERATOR_DEBUG_LEVEL é definido como 2 em compilações de depuração e como 0 em compilações de varejo.

// checked_iterators_3.cpp
// cl.exe /MTd /EHsc /W4

#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>
#include <numeric>
#include <string>
#include <vector>

using namespace std;

template <typename C>
void print(const string& s, const C& c)
{
    cout << s;

    for (const auto& e : c)
    {
        cout << e << " ";
    }

    cout << endl;
}

int main()
{
    vector<int> v(16);
    iota(v.begin(), v.end(), 0);
    print("v: ", v);

    // OK: vector::iterator is checked in debug mode
    // (i.e. an overrun causes a debug assertion)
    vector<int> v2(16);
    transform(v.begin(), v.end(), v2.begin(), [](int n) { return n * 2; });
    print("v2: ", v2);

    // OK: back_insert_iterator is marked as checked in debug mode
    // (i.e. an overrun is impossible)
    vector<int> v3;
    transform(v.begin(), v.end(), back_inserter(v3), [](int n) { return n * 3; });
    print("v3: ", v3);

    // OK: array::iterator is checked in debug mode
    // (i.e. an overrun causes a debug assertion)
    array<int, 16> a4;
    transform(v.begin(), v.end(), a4.begin(), [](int n) { return n * 4; });
    print("a4: ", a4);

    // OK: Raw arrays are checked in debug mode
    // (an overrun causes a debug assertion)
    // NOTE: This applies only when raw arrays are given to C++ Standard Library algorithms!
    int a5[16];
    transform(v.begin(), v.end(), a5, [](int n) { return n * 5; });
    print("a5: ", a5);

    // WARNING C4996: Pointers cannot be checked in debug mode
    // (an overrun causes undefined behavior)
    int a6[16];
    int * p6 = a6;
    transform(v.begin(), v.end(), p6, [](int n) { return n * 6; });
    print("a6: ", a6);

    // OK: stdext::checked_array_iterator is checked in debug mode
    // (an overrun causes a debug assertion)
    int a7[16];
    int * p7 = a7;
    transform(v.begin(), v.end(), stdext::make_checked_array_iterator(p7, 16), [](int n) { return n * 7; });
    print("a7: ", a7);

    // WARNING SILENCED: stdext::unchecked_array_iterator is marked as checked in debug mode
    // (it performs no checking, so an overrun causes undefined behavior)
    int a8[16];
    int * p8 = a8;
    transform(v.begin(), v.end(), stdext::make_unchecked_array_iterator(p8), [](int n) { return n * 8; });
    print("a8: ", a8);
}

Quando você compila esse código usando cl.exe /EHsc /W4 /MTd checked_iterators_3.cpp o compilador emite um aviso, mas compila sem erro em um executável:

algorithm(1026) : warning C4996: 'std::_Transform1': Function call with parameters
that may be unsafe - this call relies on the caller to check that the passed values
are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation
on how to use Visual C++ 'Checked Iterators'

Quando executado na linha de comando, o executável gera esta saída:

v: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
v2: 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
v3: 0 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45
a4: 0 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60
a5: 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75
a6: 0 6 12 18 24 30 36 42 48 54 60 66 72 78 84 90
a7: 0 7 14 21 28 35 42 49 56 63 70 77 84 91 98 105
a8: 0 8 16 24 32 40 48 56 64 72 80 88 96 104 112 120

See also

Visão geral da biblioteca padrão do C++
Suporte ao iterador de depuração