1. C++ / Говнокод #9356

    +1007

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    #if defined( HPUX_11_31 )
    #define BDYNAMIC_CAST( CLASS, OBJECT )  (( CLASS ) ( OBJECT ))
    #else
    #define BDYNAMIC_CAST( CLASS, OBJECT )  (dynamic_cast< CLASS >(( OBJECT )))
    #endif

    чуть кофе не похлебнулся.

    при более детальном рассмотрении кода из-за которого это сделали, выяснилось что: (А) в проекте нет ни одного места где нужен динамик каст и (Б) половина наших С++ профисианалов не умеют пользоватся конст кастом (который по коду там и был им нужен, вместе со статик кастом).

    Запостил: Dummy00001, 08 Февраля 2012

    Комментарии (28) RSS

    • а какая была причина? в хпух 11.31 чего то не хватает для работы dynamic_cast? типа rtti выключено или что?
      Ответить
      • да хер их знает что они там делали и чего им там не хватало.

        это из кода библиотеки, судя по которой, многим авторам там просто мозгов не хватает.

        я бы из того же места еще больше говна напостил, но я знаю что народ здесь на тонкости С++ не падкий. и говно там монументального характера.
        Ответить
        • Давай, выкладывай, тут тонкие ценители плюсового говнеца точно найдутся.
          Ответить
    • > половина наших С++ профисианалов
      плюсану
      лично видел и переделывал говнокод вида
      class derived: public base {...};
      derived d;
      base * f() { return dynamic_cast<base *>(&d); }


      но вообще, что dynamic_cast, что const_cast - костыли, демонстрирующие неудачные архитектурные решения (либо незнание модификатора mutable)
      Ответить
      • container_type<value_type>::const_iterator iter = container.cbegin();
        while(iter!=container.cend())
            if(condition(*iter))
                do_something(const_cast<value_type&>(*iter++));
        Ответить
        • я не уловил. так а смысл тогда в контексте данный контейнер const делать? или это по религиозным (ака: стайл гайд) соображениям все констами обвешано?
          Ответить
          • Экстракт бреда, увиденного где-то и когда-то. Смысл уже потерян давно, но чует мой пушистый зад, что это больше религия, чем стиль.
            Ответить
        • по моему самое что ни на есть очередное доказательство "неудачные архитектурные решения"
          раз пользуют const_iterator, значит container константный, и нет возможности взять iterator
          но при этом пытаются засунуть value_type & значение в do_something - вывод - либо чудо-программист, писавший do_something не видит разницы между & и const &, либо всё-таки видит, и подсовывать константные вещи в него совсем не следует
          Ответить
      • mutable обычно тоже костыль. А в целом что каст что mutable делает одно и тоже.
        Ответить
        • class some {
          public:
              value_type get() const {  // const method here
                  boost::mutex::scoped_lock lk(mutex_);
                  // much shorter and clear than 
                  // boost::mutex::scoped_lock lk(const_cast<boost::mutex &>(mutex_));
                  return value_;
              }
              // ...
          private:
              boost::mutex mutable mutex_;  // always mutable 
              // ...
          };
          Ответить
          • как по мне, констность многих методов (как и объектов в контеске) есть говно. правильная констность во большинстве случаев и нужна только для того что бы создать временный объект как входной параметр при вызове метода (который по стандарту должен быть `const whatevertype &`).

            за исключением своих специальных контейнеров и примитивных независимых структур данных, констность на всем остальном в принципе не нужна.

            я честно говоря уже давно не напрягаюсь расставлением констов - потому что слишком часто потом приходится еще раз напрягатся и их убирать. (та же херня с protected/private.)

            в твоем случае мутабл мутекса, я бы точно это делал без конста. я бы еще и get() назвал get_with_lock() - что бы в глаза прыгало что локи вовлечены.

            ЗЫ оригинальный юз-кейс мутабла это внутренний кэш, который может менятся при вызове констного гет()а. ну да почти аналогично твоему примеру.
            Ответить
            • ну раз даже ты используешь whatever const & при передаче аргумента, то ты должен понимать, что ни к каким иным методам whatever, кроме как константным, ты обратиться не сможешь

              ну и "часто напрягаться и их убирать" - это подозрительно как то, очень
              если мы хотим почитать состояние объекта, а не пописать его состояние => нет проблем сразу его объявлять const, т.е. если метод с именем get_*, то практически наверняка он обязан быть константным

              это будет верно, даже если ты может никогда не собираешься воспользоваться константностью оного - в любом случае оно будет показывать строгую безопасность использования этого метода у объекта
              поэтому если уж приходится убирать const (у тех методов, которые не должны были изменять объект) - это действительно странно, ошибка проектирования?

              и не только для временных объектов и передаче аргументов - любое применение const_iterator по контейнеру тоже вскроет проблемы

              > get() / get_with_lock() - что бы в глаза прыгало что локи вовлечены
              иногда нужно как раз чтобы не прыгало - чтобы внутренняя реализация не мозолила ничего, и пользователю этого метода не важно что происходит внутри
              Ответить
              • я вообщем согласен.

                > это действительно странно, ошибка проектирования?

                проектирование зависит от поставленых требований. даже после 2-3 лет в эксплуатации, требования меняются. это и влечет за собой что спроектированое нужно перепроектировать без полного переписывания софта.

                то что прежде считалось константным и/или "деталями реализации" потом часто становится именно тем местом где и начинается разработка новых фич.

                > ну раз даже ты используешь whatever const & при передаче аргумента

                я говорил о том что этот конст там по стандарту стоит - временные объекты ты ни как по другому не передашь. в роли этих временных объектов почти никогда не встретишь центральные/важные объекты программы - потому что они относительно тяжелые - только мелочевку, которую по дешевке можно плодить на стеке в неограниченых количествах.

                а если уж реч идет про центральные/важные объекты программы, то вот как раз тут я всей этой фигней с констами/прайвит/протектед и не страдаю.


                из недавних примеров. чудаки замутили новый модуль. дезайн - пальчики оближешь: все красиво/етц, абстрактные интерфейсы имеющие смысл, консты где надо, протектед/прайвит и все прочее. все грамотно. но. пол года спустя понадобилось добавить статистику утилизации/лайф-сайкла объектов - и вот тут веселуха началась: что бы красивый дизайн "не портить," все было обвешено где только можно френдами и const_cast'ами и даже кто-то про мутабл вспомнил в паре мест. а как по мне - в жопу дезайн который теперь больше не подходит: в паре десятков мест убрать консты и прайвиты/протектеды, и спокойно инкрементить счетчики/вычитывать статистику из внутреннего представления. потому что это внутренее представление уже не есть личное дело класса: оно уже наружу выставлено статистикой.

                вообщем, я с тобой не не согласен. мы просто про те же самые вещи с разных точек зрения говорим. :)
                Ответить
                • > private/protected не страдаю
                  и снова я в смущениях

                  не буду лезть в чужую кухню или тем более чему то поучать
                  наверное, самое первое приходящее на ум для лайф-сайкла объекта - class some: public virtual stat, ... { ... } не подошло
                  Ответить
                  • то что я хотел сказать. народ часто слишком сильно зацикливается на дизайне, а потом все что в дизайн не подходит, но реализовывать надо, делается через Ж - потому что "в дизайн не подходит ну и фиг с ним."

                    дизайн он как вера - в "религия против идеи" (если кто кино Догма помнит): идею поменять легко, поменять религию намно сложнее.
                    Ответить
                    • <много текста>

                      если возникают существенные проблемы в константности методов, обязанных быть константными, если возникают существенные проблемы в приватности членов, обязанных быть приватными - проблема не в консерватории

                      в ООП не так много базовых принципов, и если кому то настолько не подходит ООП, то только потому, что его плохо приготовили, а не потому что оно плохое - это касается любой парадигмы - поэтому до software architect надо расти, в т.ч. путем собственных ошибок и исправлений

                      безусловно, у исходников на любом языке и при любой парадигме есть свой жизненный цикл, и плох тот программист, который смотрит на свой код 5 летней давности и не видит в нем плохих мест
                      я и сам много проектов на C89 делал, доводилось - в той же процедурной парадигме у долгоживущего проекта, регулярно раз в квартал обрастающего всё новыми фичами, наступает момент, когда статических и глобальных переменных уже настолько много, что безумно хочется треть проекта переделать с чистого листа - так что костыли случаются при любой парадигме
                      Ответить
                    • и твои затирания private/protected/const - всё те же костыли, безусловно костыли, которые иногда продлевают жизнь негодной структуре, а иногда являются свидетельством того, что программист не осилил годную структуру, снес пару несущих стенок и пристроил ненужный деревянный сарай

                      сам же жалуешься, что ваши С++ профессионалы не осилили динамик-каст/конст-каст, может это как раз и второй случай

                      я не знаю насколько там у вас всё многопоточненько, я бы никогда не рискнул грязными пальцами залезть в приватные члены объекта и прочитать оттуда неконсистентные данные, я бы спросил у этого объекта - а скопируй ка мне, милок, атомарно всю ту инфу, которая мне нужна

                      и если бы в изначальном дизайне этих счетчиков не было бы совсем - я бы их вообще вынес в отдельную сущность stat - наследованием или параметром - пусть объект самостоятельно модифицирует то, что ему нужно и когда ему нужно, а я потом этот stat почитаю атомарненько методом get() const

                      > идею поменять легко - раз уж взялись за гуж ООП, так осиливайте

                      </много текста>
                      Ответить
                      • блииин, как же мне не хватает в проекте соратников, которые при виде говённого кода не говорят "Окэй... сейчас вот тут допишу говяшку...", а рефакторят, приводят к читаемому виду и пишут человеческие тесты.
                        Ответить
                        • дык не всегда для рефакторить есть время
                          ну и должна быть либо железная воля и стальные яйца, либо жизненная необходимость разрушить до основанья а затем
                          а так обычно бывает, что никто кроме программистов не видит свой говнокод, поэтому им может быть безумно стыдно перед самими собой, но заказчик вроде как и удовлетворен, поэтому поднимается вверх рука и со словами "да хер с ними!" уже никто никуда не рефакторит - а через месяц - не ну оно же уже работает, давайте просто допишем еще немного говняшки, сроки сроки

                          вот такая вот она жизнь
                          Ответить
                          • да.

                            на самом деле бесит, то как оно у меня сейчас на фирме.

                            R&D не может делать нормально - потому что их постоянно по срокам подрезают. поэтому там и живется хорошо только тем кто либо по 12 часов в день работает, либо говнокодит по быструхе как продакт манагемент повелел в установленые сроки.

                            я (в суппорте) переделать на нормально не могу, потому что в С++ программах это влечет за сабой перекомпиляцию всего проекта с последующим гигантским размером нового патч левела.

                            по крайней мере у меня в суппорте есть свобода мелкими порциями это делать. в R&D им (официальным языком) просто не дают бюджета на это. и им самим дефекты себе открывать запрещено. нет дефекта - не можешь вчекинть - всего хорошего.
                            Ответить
                            • я вообще если честно слабо представляю, как на ООП в С++ можно сделать хороший продукт, способный обновляться "частично" - разве что сообщаться между модулями голыми интерфейсами (привет, СОМ?), модули делать высокогранулярными - практически один класс = один модуль, тотально положить хер на шаблоны (иначе не взлетит) - ну и в итоге получить вместо C++ дай бог уютную джаффку, но скорее с попоболью вселенского масштаба

                              ну еще, наверное, вариант побитового diff .dll/.exe между версиями

                              как хорошо, что каждый наш софт не занимает N гигов и обновляется в автоматическом режиме по принципу "о, апдейт!" -> "удаляем всё старое нахер" -> "ставим новую версию нахер"
                              Ответить
                              • > ставим новую версию нахер
                                Инсталляция новой версии продукта на хер успешно завершена!
                                Ответить
                                • кстати милый микрософт сильно напряг в свое время со своей невозможностью в msi устанавливать предыдущую версию того же продукта
                                  казалось бы, кому какое дело - удали старое никому не нужное да установи что просят, скотина бездушная
                                  приходится в екзешник оборачивать, который сам ищет, стоппит, удаляет, чистит, запускает msi
                                  Ответить
            • Констаность, разумеется, нужна.

              "Напрягаться и убирать" - это не проблема констанности, а проблема автора кода, который не понял, какая идея константности была реализована (т.е. логическая, физическая, или что-то посередине), поленился в этом разобраться и вместо этого просто сносит все нафиг. Это просто банальная лень, на какое-то "говно" в константности.
              Ответить
    • Простите, что? Если там не самом деле нужен был 'const_cast', что ваш код не мог компилировться в принципе - 'dynamic_cast' не покрывает функциональности 'const_cast', т.е. для сноса константности использован быть не может. Если у вас 'dynamic_cast' работал в роли 'const_cast', то эт означает, что у вас - кривой компилятор. Ну а с кривым компилятором иногда и не так извращаться приходится...
      Ответить
      • это я слегка переупростил то что там код делает. там где этот дефайн больше всего используется (и для этого модуля этот #if вводили), код преимущественно выглядит приблизительно так:

        const ClassIntf *a;
        ClassImpl b = *BDYNAMIC_CAST( ClassImpl *, a );


        ну да модуль не мой. к счастью.
        Ответить

    Добавить комментарий