понедельник, 5 июля 2010 г.

[prog.flame] Вот за что мне не нравится C++

…так это за “хрупкость” результатов компиляции и линковки. Приведу пару примеров, с которыми довелось столкнуться в конце прошлой недели.

В первом эпизоде довелось поучаствовать самому. Подошел ко мне коллега, который пожаловался, что пару дней долбется с проблемой возникновения Access Violation буквально на ровном месте. Он занимался доработкой чужой программы, изменил одну из структур и в месте, которое раньше прекрасно работало, стал выскакивать злобный AV. Причем отладчик указывал в какие-то дебри реализации STL-я и понять, почему мы туда попали не представлялось возможным.

Когда я покурил проблемные исходники, мне стало понятно, что в самом месте возникновения AV проблемы нет, там нормальный корректный код. Значит, раз ошибка таки возникает, эта ошибка является наведенной – где-то в другом месте происходит “расстрел” памяти, а затем здесь его последствия “аукаются”.

С не самым лучшим настроением, предвкушая длительное бодание с чужим кодом я сделал себе checkout исходников из репозитория, скомпилировал, запустил… И ошибки не возникло.

Мой коллега пользовался Visual Studio, в том числе и для компиляции. Полного cleanup-а проекта он давно не делал. Что там в результате многих компиляций и инкрементальной линковки получалось – фиг знает. В конце-концов что-то срослось не так и на ровном месте возникал AV. Зато полный cleanup с последующим полным build-ом устранил проблему совсем.

Сам-то я еще в середине 90-х выработал для себя простое правило – если в большом C++ проекте начинают выскакивать непонятные глюки, самое первое, что нужно сделать – выполнить полный rebuild (т.е. сначала хардкорный cleanup, затем build с “чистого листа”). Не буду утверждать, что это помогало в 50% случаев, но помогало часто.

О втором эпизоде я прочитал в блоге Стива Хьюстона (одного из главных разработчиков библиотеки ACE и C++ной реализации AMQP в Apache-вском проекте). Перескажу вкратце: человек убил 5 часов рабочего времени на поиск проблемы с использованием ACE_INET_Addr. Оказалось, что сама библиотека ACE компилировалась с опцией ACE_HAS_IP6 и в ее представлении структуры ACE_INET_Addr было отведено место для sockaddr_in6, а вот приложение – без опции ACE_HAS_IP6, соответственно, в ее представлении структуры ACE_INET_Addr структуры sockaddr_in6 не было. Понятное дело, что когда экземпляр ACE_INET_Addr попадал из кода приложения в код ACE, приходил маленький пушной зверек.

Когда я был молодым, полным сил и задора, мне казалось, что все это херня. Что в правильных руках и с правильными инструментами ничего подобного не происходит, а С++ – самый лучший язык программирования :/

Теперь же, когда я узнаю, что мы теряем дни в поисках подобных проблем, остается только произнести про себя какую-нибудь банальность, вроде шит хаппенс или се-ля-ви. Ну и в очередной раз вспомнить, какой объем унаследованного C++ кода находится в нашем распоряжении, что бы очередной позыв переписать все на какой-нибудь Scala задохнулся в зародыше :(

В качестве же сухого остатка могу рассказать о простых вещах, которые я использую, чтобы не сталкиваться с подобными проблемами или минимизировать их эффект:

  • простой и надежный способ компиляции C++ных проектов. Всякие интеллектуальные инкрементальные компиляции и линковки – в топку. Лучше потерять несколько минут ожидая завершения компиляции, чем тратить часы на поиск несуществующих проблем;
  • компиляция всех сторонних библиотек вместе со своим проектом. Чтобы избежать проблем различий в настройках компилятора. Еще очень желательно, чтобы система компиляции могла проверять согласованность параметров, а так же могла распространять обязательные параметры одного подпроекта на все использующие его компоненты. Отчасти Mxx_ru это умеет, поэтому-то я Mxx_ru в свое время написал и использую его каждый день;
  • я компилирую сразу в release-режиме. Отлаживаюсь только с помощью отладочных печатей и тщательного обдумывания происходящего. Только в особо злостных случаях делаю полный rebuild в debug-режиме, чтобы воспользоваться отладчиком. После чего опять полный rebuild в release-режиме.
Отправить комментарий