Как заставить оператор std::vector [] компилировать, выполняя проверку границ в DEBUG, но не в RELEASE
Я использую Visual Studio 2008.
Мне известно, что std::vector имеет проверку границ с помощью функции at() и имеет неопределенное поведение, если вы пытаетесь получить доступ к чему-либо с помощью оператора [] неправильно (вне диапазона).
Мне любопытно, можно ли скомпилировать мою программу с проверкой границ. Таким образом, оператор [] будет использовать функцию at() и выбрасывать std::out_of_range всякий раз, когда что-то выходит за пределы.
Режим освобождения будет скомпилирован без проверки границ для оператора [], поэтому производительность не ухудшится.
Я задумался об этом, потому что я переносил приложение, написанное с использованием Borland C++, в Visual Studio, и в небольшой части кода у меня есть это (с i=0, j=1):
v[i][j]; //v is a std::vector<std::vector<int> >
Размер вектора 'v' равен [0][1] (поэтому элемент 0 вектора имеет только один элемент). Это неопределенное поведение, я знаю, но Borland возвращает 0 здесь, VS падает. Мне нравится сбой лучше, чем возвращать 0, поэтому, если я смогу получить больше "падений" при возникновении исключения std::out_of_range, миграция будет завершена быстрее (поэтому будет выявлено больше ошибок, которые скрывал Борланд).
6 ответов
Visual Studio 2005 и 2008 уже выполняют проверку границ operator[]
по умолчанию как в отладочной, так и в выпускной сборках.
Макрос для управления этим поведением _SECURE_SCL
, Установите 0, чтобы отключить проверку границ.
Их текущий план в VS2010 состоит в том, чтобы отключить проверку границ по умолчанию в сборках релиза, но оставить его включенным в режиме отладки. (Макрос также переименовывается в _ITERATOR_DEBUG_LEVEL
, Я не знаю, есть ли еще какая-либо официальная документация по нему, но это было упомянуто здесь и здесь)
Включите флаг _GLIBCXX_DEBUG для проверки границ контейнеров STL, как описано здесь: http://gcc.gnu.org/onlinedocs/libstdc++/manual/debug_mode.html
Я спросил это слишком преждевременно, но я все равно публикую ответ, поэтому делюсь некоторыми знаниями.
Stl, реализованный в Visual Studio, уже выполняет проверку границ при компиляции в режиме отладки. Это можно увидеть на <vector>
заголовок:
reference operator[](size_type _Pos)
{ // subscript mutable sequence
#if _HAS_ITERATOR_DEBUGGING
if (size() <= _Pos)
{
_DEBUG_ERROR("vector subscript out of range");
_SCL_SECURE_OUT_OF_RANGE;
}
#endif /* _HAS_ITERATOR_DEBUGGING */
_SCL_SECURE_VALIDATE_RANGE(_Pos < size());
return (*(_Myfirst + _Pos));
}
так что есть проверка границ для векторного класса. Я не смотрел на другие контейнеры, но уверен, что у них одинаковый механизм.
У меня нет доступа к любой машине Windows сейчас. Но если я посмотрю на реализацию STL, поставляемую с g++ на моем компьютере Mac OS X, из /usr/include/c++/4.0.0/bits/stl_vector.h:
// element access
/**
* @brief Subscript access to the data contained in the %vector.
* @param n The index of the element for which data should be
* accessed.
* @return Read/write reference to data.
*
* This operator allows for easy, array-style, data access.
* Note that data access with this operator is unchecked and
* out_of_range lookups are not defined. (For checked lookups
* see at().)
*/
reference
operator[](size_type __n)
{ return *(begin() + __n); }
Проверка не выполнена, событие в режиме отладки. Никакая _GLIBCXX_DEBUG marcro не проверяется здесь в этом коде.
Взгляните на свою собственную реализацию STL, поставляемую с MSVC, и посмотрите, что сделано. Если в любом случае проверка не выполняется... у вас нет выбора, кроме как использовать at()..:-(
Для людей, использующих QT, добавьте следующую строку в файл .pro:
CONFIG(debug, debug|release ):DEFINES += _GLIBCXX_DEBUG
PS Когда я добавил эту строку, компилятор выдал много ошибок. Я удалил все файлы, созданные компилятором, в каталоге сборки, перекомпилировал проект, и ошибки исчезли.
C++ определяет векторный оператор [] как не вызывающий исключение ради скорости.
Я бы посоветовал вам протестировать приложение в конфигурации отладки некоторое время, пока вы не обретете уверенность в том, что основные "скрытые" ошибки исчезли.