Мало кто знает, но компиляторы и стандартная библиотека C++ могут проверять выходы за границы массивов и векторов.
Если мы используем gcc и glibc, то следующий код бросит исключение:
#define _GLIBCXX_DEBUG
#include <bits/stdc++.h>
int main() {
std::vector <int> a(100);
int x = -1;
printf("%d\n", a[x]);
}
И мы получим примерно вот такой вывод: error: attempt to subscript container with out-of-bounds index -1, but container only holds 100 elements.
Номер строки мы не узнаем, но лучше, чем ничего. С этим флагом все контейнеры С++ включают проверки на ошибки (кроме C++11 std::array, как я понял). Также можно не писать define прямо в коде, а передавать аргумент компилятору: g++ -D_GLIBCXX_DEBUG main.cpp -o main
А что делать с массивами? Для проверки выхода за границы массива предусмотрен флаг -fsanitize=bounds. Правда у меня его gcc(4.7.3) не принял, сказав, что неизвестный флаг, но clang скомпилировал.
#include <bits/stdc++.h>
int main() {
int a[100];
int x = -1;
printf("%d\n", a[x]);
}
Компилируем вот так: clang++ main.cpp -fsanitize=bounds -o main
При запуске получаем: test.cpp:6:20: runtime error: index -1 out of bounds for type 'int [100]
Еще более дружелюбный вывод, чем в случае с векторами.
К сожалению c динамическими массивами (int *a = new int[100]) такое не работает, но есть еще флаг -fsanitize=undefined (включает в себя bounds) и -fsanitize=adress, который как раз уронит вариант с динамическим массивом.
UPD: WARNING: Не отсылайте решения с этим макросом в коде, неизбежно получите ТЛ.
UPD2: Чтобы использовать -fsanitize нужен gcc >=4.9 или clang
Неплохо было бы уточнить как меняется быстродействие с флагом и без.
Плюс у скептиков может появиться вопрос "если так хочется проверять границы массива, чего б не писать на
C#
илиJava
?" Или хотя бы не юзать голые массивы вместо вектора. :)http://codeforces.me/contest/436/submission/7866283
http://codeforces.me/contest/436/submission/7866353
Дебаг векторов замедлил программу как минимум в 10 раз. Вывод — не надо сабмитить с таким флагом, он нужен только, чтобы тестировать локально.
Дебаг массивов не могу проверить, потому что там из кода никак нельзя его включить, да и под gcc я так и не понял как его включить. Локально использую clang.
Почему не писать на java — тут уж кому что больше нравится, я очень много и долго писал все на java, но в последнее время почти всегда пишу на плюсах. Не из-за скорости, просто мне так приятнее, что-то переключило и вернулся на плюсы, на java теперь когда приходится с некоторым отвращением пишу)
Нужен GCC 4.9, тогда работает
-fsanitize=address,undefined
.Спасибо, написал в посте.
Фундаментальное отличие в этом плане такое, что в C++ я могу выбрать, что я хочу: либо проверки выхода за границы, либо быстрое выполнение программы. Соответственно, при написании и отладке программы я использую первое, когда отсылаю на проверку — второе. В С#/Java такого выбора просто нет.
Тогда уж лучше компилировать с -D_GLIBCXX_DEBUG, чтобы случайно не отослать код с этим макросом в тестирующую систему.
хм...)
Would you translate this to English please?
Briefly, the post says that the
_GLIBCXX_DEBUG
define causes throwing exceptions when trying to access an STL container at an out-of-bounds index, and the-fsanitize=address,undefined
command line key for compilers does a simular trick with the arrays. Of course, it affects performance pretty much, so it’s a bad idea to submit the code containing#define _GLIBCXX_DEBUG
.