Zaznaczone iteratory
Iteratory sprawdzane zapewniają, że granice kontenera nie ulegają nadpisaniu.
Iteratory sprawdzane mają zastosowanie do kompilacji oficjalnych i przeznaczonych do debugowania.Aby uzyskać więcej informacji o sposobach używania iteratorów podczas kompilacji w trybie debugowania, zobacz Obsługa iteratora debugowania.
Uwagi
Aby uzyskać informacje na temat sposobu wyłączania ostrzeżeń generowanych przez iteratory sprawdzane, zobacz _SCL_SECURE_NO_WARNINGS.
Z funkcją iteratorów sprawdzonych można używać następującego symbolu.
- _SECURE_SCL
Jeśli opcja _SECURE_SCL jest zdefiniowana jako 1, niebezpieczne używanie iteratorów powoduje błąd czasu wykonywania, a program zostaje zakończony.Jeśli jest zdefiniowana jako 0, iteratory sprawdzane są wyłączone.Domyślnie wartość dla _SECURE_SCL to 0 dla kompilacji oficjalnych i 1 dla kompilacji przeznaczonych do debugowania.
Ważne |
---|
Używaj _ITERATOR_DEBUG_LEVEL w celu kontroli _SECURE_SCL.Aby uzyskać więcej informacji, zobacz _ITERATOR_DEBUG_LEVEL. |
Gdy opcja _SECURE_SCL jest zdefiniowana jako 1, wykonywane są następujące sprawdzenia SCL:
Wszystkie standardowe iteratory (na przykład vector::iterator) są sprawdzane.
Jeśli iterator wyjściowy jest iteratorem sprawdzonym, uzyskasz sprawdzane zachowanie dla wywołań funkcji standardowej (na przykład std::copy).
Jeśli iterator wyjściowy jest iteratorem niesprawdzonym, wywołanie standardowej funkcji spowoduje ostrzeżenia kompilatora.
Następujące funkcje wygenerują błąd czasu wykonywania, jeśli nastąpi dostęp poza granicami kontenera:
Gdy opcja _SECURE_SCL jest zdefiniowana jako 0:
Wszystkie standardowe iteratory są niesprawdzane (iteratory można przenosić poza granice kontenera, co prowadzi do niezdefiniowanego zachowania).
Jeśli iterator wyjściowy jest iteratorem sprawdzonym, uzyskasz sprawdzone zachowanie dla wywołań funkcji standardowej (na przykład std::copy).
Jeśli iterator wyjściowy jest iteratorem niesprawdzonym, uzyskasz niesprawdzone zachowanie dla wywołań funkcji standardowej (na przykład std::copy).
Iterator sprawdzony odnosi się do iteratora, który będzie wywoływał invalid_parameter_handler, jeśli próbujesz wyjść poza granice kontenera.Aby dowiedzieć się więcej o obiekcie invalid_parameter_handler, zobacz Sprawdzanie poprawności parametru.
checked_array_iterator — Klasa i unchecked_array_iterator — Klasa to adaptery iteratora, które obsługują sprawdzane iteratory.
Przykład
Gdy kompilujesz przy użyciu _SECURE_SCL 1, wystąpi błąd czasu wykonywania, jeśli spróbujesz uzyskać dostępu do elementu, który znajduje się poza granicami kontenera, za pomocą operatora indeksowania niektórych klas.
// checked_iterators_1.cpp
// cl.exe /Zi /MDd /EHsc /W4
#define _ITERATOR_DEBUG_LEVEL 1
// implies #define _SECURE_SCL 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
};
Ten program wyświetli „67”, a następnie wyświetli okno dialogowe błędu asercji z dodatkowymi informacjami dotyczącymi błędu.
Podobnie, gdy kompilujesz przy użyciu _SECURE_SCL 1, wystąpi błąd czasu wykonywania, jeśli spróbujesz uzyskać dostęp do elementu przy użyciu przodu lub tyłu niektórych klas, gdy kontener jest pusty.
// checked_iterators_2.cpp
// cl.exe /Zi /MDd /EHsc /W4
#define _ITERATOR_DEBUG_LEVEL 1
// implies #define _SECURE_SCL 1
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector<int> v;
int& i = v.front(); // triggers invalid parameter handler
};
Ten program wyświetli okno dialogowe błędu asercji z dodatkowymi informacjami dotyczącymi błędu.
Poniższy kod demonstruje różne scenariusze użycia iteratorów wraz z komentarzami dotyczącymi każdego z nich.
// 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 will trigger 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 will trigger 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 will trigger a debug assertion)
// NOTE: This applies only when raw arrays are given to STL 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 will trigger 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 will trigger 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 will trigger 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);
}
Dane wyjściowe
Kodu pokazany w poprzedniej sekcji kompilowany z cl.exe /EHsc /W4 /MTd spowoduje następujące ostrzeżenie kompilatora, ale skompiluje się bez błędów do pliku wykonywalnego:
algorithm(1026) : warning C4996: 'std::_Transform1': Function call with parameters that may be unsafe - this call rel
ies 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'
Uruchomienie pliku wykonywalnego aplikacji konsoli daje następujący wynik:
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