Я пишу кроссплатформенную программу на C ++ для Windows и Unix. На стороне окна код компилируется и выполняется без проблем. Со стороны Unix он компилируется, однако, когда я пытаюсь запустить его, я получаю ошибку сегментации. Моя первоначальная догадка заключается в том, что есть проблема с указателями.
Каковы хорошие методологии поиска и исправления ошибок ошибок сегментации?
источник
g
в контекстеCMake
?cmake -DCMAKE_BUILD_TYPE=Debug
.Иногда сбой сам по себе не является реальной причиной проблемы - возможно, память была повреждена ранее, но потребовалось время, чтобы повреждение проявилось. Посмотрите valgrind , в котором есть множество проверок на наличие проблем с указателями (включая проверку границ массива). Он скажет вам, где начинается проблема , а не только строка, где происходит сбой.
источник
До того, как возникнет проблема, постарайтесь как можно больше ее избегать:
Используйте соответствующие инструменты для отладки. В Unix:
С GCC вы также можете использовать грязевик.С GCC, Clang и с октября экспериментально MSVC вы можете использовать Address / Memory Sanitizer . Он может обнаруживать некоторые ошибки, которых не делает Valgrind, и снижает производительность. Используется при компиляции с-fsanitize=address
флагом.Наконец, я бы порекомендовал обычные вещи. Чем больше ваша программа удобочитаема, удобна в обслуживании, понятна и аккуратна, тем проще ее будет отлаживать.
источник
В Unix вы можете использовать
valgrind
для поиска проблем. Это бесплатно и мощно. Если вы не хотите сделать это самостоятельно вы можете перегрузитьnew
иdelete
операторам создать конфигурацию , в которой у вас есть 1 байт с0xDEADBEEF
до и после каждого нового объекта. Затем отслеживайте, что происходит на каждой итерации. Это может не уловить все (вы не гарантируете, что даже прикоснетесь к этим байтам), но в прошлом у меня это работало на платформе Windows.источник
new
иdelete
может быть очень полезной, использование-fsanitize=address
- лучший вариант, так как компилятор будет компилировать при обнаружении проблем во время выполнения и автоматически выгружает память на экран, что упрощает отладку.Да, проблема с указателями. Скорее всего, вы используете тот, который не инициализирован должным образом, но также возможно, что вы испортили управление памятью из-за двойных освобождений или чего-то подобного.
Чтобы избежать неинициализированных указателей в качестве локальных переменных, попробуйте объявить их как можно позже, желательно (а это не всегда возможно), когда они могут быть инициализированы значимым значением. Убедите себя в том, что они будут иметь ценность, прежде чем они будут использованы, изучив код. Если у вас возникли трудности с этим, инициализируйте их константой нулевого указателя (обычно обозначаемой как
NULL
или0
) и проверьте их.Чтобы избежать неинициализированных указателей в качестве значений членов, убедитесь, что они правильно инициализированы в конструкторе и правильно обрабатываются в конструкторах копирования и операторах присваивания. Не полагайтесь на
init
функцию для управления памятью, хотя вы можете для другой инициализации.Если вашему классу не нужны конструкторы копирования или операторы присваивания, вы можете объявить их как частные функции-члены и никогда не определять их. Это вызовет ошибку компилятора, если они используются явно или неявно.
По возможности используйте умные указатели. Большим преимуществом здесь является то, что если вы будете придерживаться их и использовать их последовательно, вы можете полностью избежать записи,
delete
и ничего не будет дважды удалено.По возможности используйте строки и классы контейнеров C ++ вместо строк и массивов в стиле C. Рассмотрите возможность использования
.at(i)
вместо[i]
, потому что это приведет к принудительной проверке границ. Посмотрите, можно ли настроить ваш компилятор или библиотеку для проверки границ на[i]
, по крайней мере, в режиме отладки. Ошибки сегментации могут быть вызваны переполнением буфера, которое приводит к записи мусора по совершенно исправным указателям.Выполнение этих действий значительно снизит вероятность ошибок сегментации и других проблем с памятью. Они, несомненно, не смогут исправить все, поэтому вам следует использовать valgrind время от времени, когда у вас нет проблем, и valgrind и gdb, когда они есть.
источник
Я не знаю какой-либо методологии, чтобы исправить подобные вещи. Я не думаю, что можно было бы придумать что-то одно, потому что проблема заключается в том, что поведение вашей программы не определено (я не знаю ни одного случая, когда SEGFAULT не был вызван каким-то UB) .
Существуют всевозможные «методики», позволяющие избежать проблемы до того, как она возникнет. Один из важных - RAII.
Кроме того, вам просто нужно направить на это свои лучшие психические энергии.
источник