The following symbols are for use with the checked iterators feature.
-
_SECURE_SCL
-
If defined as 1, unsafe iterator use causes a runtime error. If defined as 0, checked iterators are disabled. The exact behavior of the runtime error depends on the value of _SECURE_SCL_THROWS. The default value for _SECURE_SCL is 1, meaning checked iterators are enabled by default.
-
_SECURE_SCL_THROWS
-
If defined as 1, an out of range iterator use causes an exception at runtime. If defined as 0, the program is terminated by calling invalid_parameter. The default value for _SECURE_SCL_THROWS is 0, meaning the program will be terminated by default. Requires _SECURE_SCL to also be defined.
When _SECURE_SCL=1 is defined:
All standard iterators (vector::iterator, for example) are checked.
The checked form of an algorithm will be used, for standard functions with checked forms (see list below).
If an output iterator is a checked iterator:
You will get checked behavior on calls to the standard function (std::copy, for example).
You will get checked behavior on calls to a checked function (stdext::checked_copy, for example).
You will get checked behavior on calls to an unchecked function (stdext::unchecked_copy, for example).
If the output iterator is an unchecked iterator (an array, for example):
Calls to the standard function (std::copy, for example) will result in compiler warnings.
Calls to the checked function (stdext::checked_copy, for example) will result in compiler warnings.
You will get unchecked behavior on calls to an unchecked function (stdext::unchecked_copy, for example).
The following functions will generate a runtime error if there is an access outside the bounds of the container:
When _SECURE_SCL=0 is defined:
All standard iterators are unchecked (same behavior as specified by the C++ standard).
The unchecked form of a function will be used, for standard functions with checked forms (see list below).
If an output iterator is a checked iterator:
You will get checked behavior on calls to the standard function (std::copy, for example).
You will get checked behavior on calls to a checked function (stdext::checked_copy, for example).
You will get checked behavior on calls to an unchecked function (stdext::unchecked_copy, for example).
If an output iterator is an unchecked iterator:
You will get unchecked behavior on calls to the standard function (std::copy, for example).
Calls to a checked function (stdext::checked_copy, for example) will result in compiler warnings.
You will get unchecked behavior on calls to an unchecked function (stdext::unchecked_copy, for example).
A checked iterator refers to an iterator that will throw an exception or call invalid_parameter if you attempt to move past the boundaries of the container. For more information about invalid_parameter, see Parameter Validation.
A checked algorithm enforces the use of a checked destination iterator. A checked algorithm will not pass compilation if passed an unchecked destination iterator.
There are two iterator adaptors that support checked iterators:
The following algorithms enforce the use of a checked iterator as output iterator. This is useful when you want to compile with _SECURE_SCL=0, and where you identify some code where you want to enforce the use of checked iterators. The following algorithms are all defined in the stdext namespace.
The following algorithms allow the use of an unchecked iterator as output iterator. This is useful when you want to compile with _SECURE_SCL=1, and where you want to selectively allow the use of unchecked iterators. The following algorithms are all defined in the stdext namespace.
When compiling with _SECURE_SCL 1, a runtime error will occur if you attempt to access an element outside the bounds of the container with the indexing operator of certain classes (see above).
// checked_iterators_1.cpp
// compile with: /EHsc
#define _SECURE_SCL 1
#define _SECURE_SCL_THROWS 1
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<int> v;
v.push_back(67);
int i = v[0];
cout << i << endl;
try {
i = v[1];
}
catch (std::out_of_range) {
cout << "invalid container access" << endl;
}
};
Output
When compiling with _SECURE_SCL 1, a runtime error will occur if you attempt to access an element with front or back of certain classes (see above), when the container is empty.
在保证C++标准库的安全特性的同时,Visual C++2005继续坚持并在很多情况下改进了C++标准库的运行特性,同时提供了调节C++标准库安全性的特色。一项受人欢迎的改进是在调试版本中添加了范围检查,这对你的发行版本性能并不构成影响。但这确实帮助你在调试阶段捕获越界错误,甚至是使用传统上不安全的下标操作符的代码。
不安全的函数,象vector的下标操作算子,和其他的函数,象它的front函数,如果不恰当的调用,通常会导致不明确的行为。如果你幸运的话,它将很快导致一个存取冲突,这将使你的应用程序崩溃。如果你不那么走运的话,它可能默默地持续运转并导致不可预知的副效应,这将破坏数据并可能被进攻者利用。为了保护你的发行版本的应用程序,Visual C++2005引入了_SECURE_SCL符号,用来给那些非安全的函数添加运行时检查。象下面的代码那样在你的应用程序中简单地定义这个符号可以添加额外的实时检查并阻止不确切的行为。
#define _SECURE_SCL 1
紧记定义这个符号对你的程序冲击很大,大量的合法的,但是具有潜在非安全的操作将在编译时将无法通过,以避免在运行时出现潜在BUG。思考下面的使用Copy运算的例子:
std::copy(first, last, destination);
其中,first和last是定义拷贝范围的迭代参数,destination是输出迭代参数,指示了目标缓冲区的位置,这个位置用来拷贝范围之内的第一个元素。这里有一个危险是destination所对应的目标缓冲区或容器不足够大,无法容纳所要拷贝的元素。如果Destination是一个需要安全检查的迭代参数,类似的错误将被捕获。但是,这仅仅是一个假设。如果destination是一个简单的指针,将无法保证copy运算函数正确运转。这时当然会想到_SECURE_SCL符号来避免这一问题,这种情况下,代码甚至是不能编译,以此避免任何可能的运行时错误。就象你想象的那样,这将需要重写更完美有效的代码。所以,这是一个更好的理由支持C++标准库容器,避免使用C类型数组。
// checked_iterators_2.cpp // compile with: /EHsc #define _SECURE_SCL 1 #define _SECURE_SCL_THROWS 1 #include <vector> #include <iostream> int main() { using namespace std; vector <int> v1; try { int& i = v1.front(); } catch (std::out_of_range) { cout << "vector is empty!!" << endl; } }
Output
When compiling with _SECURE_SCL 1, the compiler enforces the use of a checked iterator on standard algorithms that also have checked and unchecked versions (see above).
// checked_iterators_3.cpp // compile with: /EHsc /W1 #define _SECURE_SCL 1 #include <algorithm> #include <iostream> using namespace std; using namespace stdext; int main() { int a [] = {1,2,3}; int b [10]; copy(a, a + 3, b); // C4996 unchecked iterator copy(a, a + 3, checked_array_iterator<int*>(b, _countof(b))); // OK }
The following example sets _SECURE_SCL to 0, thus disabling checked iterators. With checked iterators disabled, you must take extra caution to ensure you do not iterate beyond the bounds of your container.
// checked_iterators_4.cpp // compile with: /EHsc #define _SECURE_SCL 0 #include <vector> #include <iostream> using namespace std; int main() { vector<int> v; v.push_back(67); int i = v[0]; cout << i << endl; };