Dela via


Checked Iterators

Kontrollerade iteratorer ser till att gränserna för containern inte skrivs över. Kontrollerade iteratorer gäller både versionsversioner och felsökningsversioner. Mer information om hur du använder felsöknings iteratorer när du kompilerar i felsökningsläge finns i Felsökningsstöd för Iterator.

Remarks

Information om hur du inaktiverar varningar som genereras av kontrollerade iteratorer finns i _SCL_SECURE_NO_WARNINGS.

Du kan använda makrot _ITERATOR_DEBUG_LEVEL för förprocessorn för att aktivera eller inaktivera den markerade iteratorfunktionen. Om _ITERATOR_DEBUG_LEVEL definieras som 1 eller 2 orsakar osäker användning av iteratorer ett körningsfel och programmet avslutas. Om det definieras som 0 inaktiveras kontrollerade iteratorer. Som standard är värdet för _ITERATOR_DEBUG_LEVEL 0 för versionsversioner och 2 för felsökningsversioner.

Important

Äldre dokumentation och källkod kan referera till makrot _SECURE_SCL . Använd _ITERATOR_DEBUG_LEVEL för att styra _SECURE_SCL. Mer information finns i _ITERATOR_DEBUG_LEVEL.

När _ITERATOR_DEBUG_LEVEL definieras som 1 eller 2 utförs dessa iteratorkontroller:

  • Alla standard iteratorer (till exempel vector::iterator) kontrolleras.

  • Om en iterator för utdata är en kontrollerad iterator anropar anrop till standardbiblioteksfunktioner som std::copy att få kontrollerat beteende.

  • Om en iterator för utdata är en okontrollerad iterator orsakar anrop till standardbiblioteksfunktioner kompilatorvarningar.

  • Följande funktioner genererar ett körningsfel om det finns en åtkomst som ligger utanför containerns gränser:

När _ITERATOR_DEBUG_LEVEL definieras som 0:

  • Alla standard iteratorer är avmarkerade. Iteratorer kan flyttas utanför containergränserna, vilket leder till odefinierat beteende.

  • Om en iterator för utdata är en kontrollerad iterator anropar anrop till standardbiblioteksfunktioner som std::copy att få kontrollerat beteende.

  • Om en iterator för utdata är en omarkerad iterator får anrop till standardbiblioteksfunktioner omarkerat beteende.

En markerad iterator refererar till en iterator som anropar invalid_parameter_handler om du försöker gå förbi containerns gränser. Mer information om invalid_parameter_handlerfinns i Parameterverifiering.

Iteratoradaptorerna som stöder kontrollerade iteratorer är checked_array_iterator Klass och unchecked_array_iterator Klass.

Examples

När du kompilerar med inställningen _ITERATOR_DEBUG_LEVEL 1 eller 2 uppstår ett körningsfel om du försöker komma åt ett element som ligger utanför containerns gränser med hjälp av indexeringsoperatorn för vissa klasser.

// 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
}

Det här programmet skriver ut "67" och öppnar sedan en dialogruta för kontrollfel med ytterligare information om felet.

När du kompilerar med inställningen _ITERATOR_DEBUG_LEVEL 1 eller 2 uppstår på samma sätt ett körningsfel om du försöker komma åt ett element med hjälp front av eller back i containerklasser när containern är tom.

// 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
}

Det här programmet visar en dialogruta för kontrollfel med ytterligare information om felet.

Följande kod visar olika scenarier för iteratoranvändning med kommentarer om var och en. Som standard _ITERATOR_DEBUG_LEVEL anges till 2 i Felsökningsversioner och till 0 i Detaljhandelsversioner.

// 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);
}

När du kompilerar den här koden med hjälp cl.exe /EHsc /W4 /MTd checked_iterators_3.cpp av kompilatorn genererar en varning, men kompileras utan fel till en körbar fil:

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'

När den körs på kommandoraden genererar den körbara filen följande utdata:

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

Översikt över C++-standardbibliotek
Felsökningsstöd för Iterator