Блог пользователя zakharvoit

Автор zakharvoit, 10 лет назад, По-русски

Мало кто знает, но компиляторы и стандартная библиотека 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

  • Проголосовать: нравится
  • +77
  • Проголосовать: не нравится

»
10 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Неплохо было бы уточнить как меняется быстродействие с флагом и без.

Плюс у скептиков может появиться вопрос "если так хочется проверять границы массива, чего б не писать на C# или Java?" Или хотя бы не юзать голые массивы вместо вектора. :)

  • »
    »
    10 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится +6 Проголосовать: не нравится

    http://mirror.codeforces.com/contest/436/submission/7866283

    http://mirror.codeforces.com/contest/436/submission/7866353

    Дебаг векторов замедлил программу как минимум в 10 раз. Вывод — не надо сабмитить с таким флагом, он нужен только, чтобы тестировать локально.

    Дебаг массивов не могу проверить, потому что там из кода никак нельзя его включить, да и под gcc я так и не понял как его включить. Локально использую clang.

    Почему не писать на java — тут уж кому что больше нравится, я очень много и долго писал все на java, но в последнее время почти всегда пишу на плюсах. Не из-за скорости, просто мне так приятнее, что-то переключило и вернулся на плюсы, на java теперь когда приходится с некоторым отвращением пишу)

  • »
    »
    10 лет назад, # ^ |
      Проголосовать: нравится +3 Проголосовать: не нравится

    Фундаментальное отличие в этом плане такое, что в C++ я могу выбрать, что я хочу: либо проверки выхода за границы, либо быстрое выполнение программы. Соответственно, при написании и отладке программы я использую первое, когда отсылаю на проверку — второе. В С#/Java такого выбора просто нет.

»
10 лет назад, # |
  Проголосовать: нравится -8 Проголосовать: не нравится

Тогда уж лучше компилировать с -D_GLIBCXX_DEBUG, чтобы случайно не отослать код с этим макросом в тестирующую систему.

  • »
    »
    10 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    хм...)

    Номер строки мы не узнаем, но лучше, чем ничего. С этим флагом все контейнеры С++ включают проверки на ошибки (кроме C++11 std::array, как я понял). Также можно не писать define прямо в коде, а передавать аргумент компилятору: g++ -D_GLIBCXX_DEBUG main.cpp -o main
    
    
»
10 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Would you translate this to English please?

  • »
    »
    10 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    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.