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

    +3

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    #include <iostream>
    
    using namespace std;
    
    class Base {
    public:
           Base() {
                  cout << "Base construct\n";
           }
           virtual  ~Base() {
                  cout << "Base destruct\n";
           }
    };
    
    class Child: public Base {
    public:
           Child() {
                  cout << "Child construct\n";
           }
           ~Child() {
                  cout << "Child destruct\n";
           }
    };
    
    int main() {
           Base *base = new Child();
           delete base;
    }

    Hy нe oчeвиднo жe! Для тoгo, чтoб вызывaлиcь вce дecтpyктopы, нyжнo oбъявить eгo виpтyaльным. B тo вpeмя кaк кoнcтpyктop бeз мoдификaтopa virtual paбoтaeт тaк жe, кaк виpтyaльный дecтpyктop.
    И зaчeм вoбщe ocтaвлять вoзмoжнocть нe виpтyaльнoгo дecтpyктopa - нe мoгy пpeдcтaвить ceбe cлyчaя, кoгдa пpи yдaлeнии oбъeктa нyжeн вызoв дecтpyктopa тoлькo бaзoвoгo клacca.

    Запостил: Pythoner, 18 Марта 2014

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

    • перфоманс же. Вместо разыменования и вызова по указателю будет простой вызов метода
      Ответить
    • Всё нормально, деструктор в Child будет всё равно виртуальный. Зато если захочешь отказаться от виртуальных функций и деструкторов, для производительности например, то достаточно будет только в одном Base убрать virtual. Так что совсем не говнокод, а пример как надо писать.
      Ответить
    • > зaчeм вoбщe ocтaвлять вoзмoжнocть нe виpтyaльнoгo дecтpyктopa - нe мoгy пpeдcтaвить

      Т.е. ты не можешь представить себе случай, когда класс не подразумевает наличия наследников? У меня 96.8% классов таких.
      Ответить
      • Не виртуальным имеется ввиду что не будет вызываться у наследников. По аналогии с конструктором - он всегда работает как виртуальный, т.е. вызывается для каждого класса, наследником которого является данный.
        Ответить
        • Представь себе, я знаю как работают констукторы и деструкторы в плюсах, и что называется виртуальным деструктором.

          а теперь перечитай ещё раз мой комментарий
          Ответить
          • показать все, что скрытоНе надо цитировать вырваные из контекста фразы."нe мoгy пpeдcтaвить ceбe cлyчaя, кoгдa пpи yдaлeнии oбъeктa нyжeн вызoв дecтpyктopa тoлькo бaзoвoгo клacca"
            Причем тут класс без наследников?
            Ответить
            • > Причем тут класс без наследников?
              Если у класса не должно быть наследников, зачем ему может понадобиться виртуальный деструктор?
              Правильно, не нужен.
              Ответить
            • Не поверишь, при том. Для него нужен только деструктор базы, то есть его собственный.
              Ответить
              • Хорошо, вопрос от обратного - зачем нужен конструктор, который ведет себя как виртуальный. Вот надо мне виртуальный, я бы прямым текстом написал бы - virtual.
                Ответить
                • Схуялли он ведёт себя как виртуальный?
                  new Derived - какой вызвал, такой и вызвался
                  Ответить
                  • >> конструктор, который ведет себя как виртуальный
                    > Схуялли он ведёт себя как виртуальный?

                    1. Наблюдатель удаляет объект хрен знает какого класса, имея указатель на объект класса родителя - вызывается только деструктор родителя.
                    2. Наблюдатель добавляет слово virtual к деструктору - вызываются деструкторы [b]потомков[b] и деструктор родителя.
                    3. Наблюдатель делает вывод: "виртуальный %X%", при вызове которого вызывается не только %X% потомка, но и %X% родителя.
                    4. Наблюдатель создаёт объект - вызываются конструктор родителя и конструкторы потомков.
                    5. С точки зрения наблюдателя конструктор - виртуальный.

                    UPD: Тьфу, автор уже описал этот мысленный эксперимент, но менее подробно в http://govnokod.ru/15517#comment221649. И я же читал тот комментарий...
                    Ответить
                    • а при вызове виртуально функции тоже поочерёдно вызываются все реализации
                      Ответить
      • А кроме перфоманса от невиртуальности деструктора какая-то польза есть?
        Что будет плохого, если объявить все деструкторы виртуальными, а там, где на стадии компиляции ясно, какой класс, не лезть в таблицу и вызывать сразу нужные деструкторы?
        Ответить
        • Наличие хотя бы одной виртуальной функции (деструктор тоже функция) означает, что для класса нужно сгенерировать таблицу виртуальных функций и включать указатель на неё в каждый объект. Это увеличивает размер каждого объекта, зачастую не внося никакого преимущества (часто бывают объекты размером с указатель, наличие ещё одного указателя удвоит их размер).

          Ну и это нарушает один из основопологающих принципов плюсов - не платить за то, что не используешь.

          > там, где на стадии компиляции ясно, какой класс, не лезть в таблицу и вызывать сразу нужные деструкторы?
          Это оптимизация уже давно работает для всех виртуальных функций (и деструкторов). Если компилятору точно известен тип, виртуальные функции вызываются невиртуально.
          Ответить
          • > Это увеличивает размер каждого объекта
            Не подумал об этом. А для оптимизации (удаления лишнего поля) уже потребуется перекомпилировать класс-родитель, печаль.
            Ответить
            • Поэтому я за то, чтобы виртуальных методов не было. Они противоречат идеологии крестов.
              А для динамического полиморфизма подойдёт сахар-динамитор, что-то типа более удобного tagged union.
              Ответить
        • Кстати, тут ещё и обратная совместимость вылезает. В плюсах же можно наследоваться от сишных структур, layout которых, разумеется, нельзя трогать.
          В теории можно было сказать "пусть деструктор будет виртуальным только у типов, объявленных с ключевым словом class", но это уже попахивает Д.
          Ответить
          • У наследования от сишного POD'а разве есть разумные применения?

            Да и лейаут оно не испортит, если не забывать каст (который в данном случае уже не nop).
            Ответить
            • Так сходу сложно придумать. Разве что кто-то захочет добавить к стуктурке удобных методов, не потеряв возможности запихивать её в старые функции.
              Опять же, как отличить структуру, от которой мы хотим иметь возможность наследоваться, от старой доброй сишной? Если POD - нет виртуального деструктора, если не POD - есть?

              Я за явный virtual для деструктора, explicit is better than implicit. В крестах и так слишком много сложностей на ровном месте.
              Ответить
              • > как отличить структуру
                Слово struct оставить для POD'ов, полностью запретив в них виртуальные методы, динамик каст, множественное наследование и наследование от не POD'ов.
                Слово class оставить для настоящих классов, у которых виртуальный деструктор и ТВМ никак не убираются. И запретить наследовать class от struct, ибо нехрен.

                > добавить к стуктурке удобных методов, не потеряв возможности запихивать её в старые функции.
                Вполне так решается агрегацией:
                class some_shit {
                private:
                    plain_old_data pod;
                public:
                    plain_old_data & get_plain_old_data() { return pod; }
                };
                some_shit s;
                legacy_method(s.get_plain_old_data());
                Ответить
                • руки прочь от struct!
                  меня бесит, что по умолчанию в class всё private, неудобно же
                  Ответить
                  • > неудобно же
                    О да, "public:" писать же так дооолго... В жабе вон вообще почти к каждому полю или методу пишут, и ничего, живые.

                    > руки прочь от struct!
                    Да никто никогда его не тронет :) Совместимость же.
                    Ответить
                    • писать не долго, но грязно
                      учитывая, что обычно класс/структура описывается в таком порядке, что сначала идут публичные поля, а в подвале - приватные
                      Ответить
                      • > писать не долго, но грязно
                        Да ну, я и так всегда пишу class и public: для не POD'ов... Как-то не напрягает. Юзать struct чисто ради дефолтного паблика на верхнюю половину класса, имхо, как-то не айс...

                        Убрать дефолтный private/public вообще, чтобы положить конец битве остроконечников с тупоконечниками. Пусть пишут явно в обоих случаях.
                        Ответить
                  • с другой стороны, class на 1 символ короче чем struct
                    Ответить
                • > Слово class оставить для настоящих классов, у которых виртуальный деструктор и ТВМ никак не убираются. И запретить наследовать class от struct, ибо нехрен.

                  Вам в D. Который, правда, всё равно не взлетит, т.к. самое важное в нём явно скоро доперетащат в кресты...
                  Ответить
                  • >Который, правда, всё равно не взлетит,
                    Угу. Останется в недрах лицакниги при поддержке Александреску.
                    Ответить
                    • а он ведь так и не сказал, что он там такого на 5к строк на d написал. И нужно ли оно там сейчас вообще :)
                      http://forum.dlang.org/thread/[email protected]
                      Ответить
                      • > что он там такого на 5к строк
                        Судя по всему что-то совсем небольшое и простенькое. Или D настолько компактней c++, что в такой объем войдет что-то серьезное?
                        Ответить
                        • так размер строки ж не регламентирован.
                          Ответить
                        • > D настолько компактней c++
                          На первый взгляд он максимум в 1,5-2 раза компактней. Проверять, написав что-то нетривиальное на том и на другом желания никакого, как и вообще писать что-то на D.

                          Цитирую одного из разработчиков D1:

                          Now using Eclipse + C Dev Tools (CDT) and GCC as the IDE and tool-chain respectively, I feel I'm back to really cooking on gas once again.

                          "Oh C++, why did I ever leave you?"

                          http://www.digitalmars.com/d/archives/digitalmars/D/D_hates_to_be_dynamic_linked_106525.html
                          Ответить
                          • 4 года как прошло
                            Ответить
                            • > 4 года как прошло

                              Да это всё понятно. И на сайте d написано, что как и с чем можно линковать.

                              P.S. книжка александреску вышла в том же году :)
                              Ответить
                      • ну может на DConf расскажет в конце мая.
                        Ответить
                • >Слово class оставить для настоящих классов,
                  шарпопуть
                  Ответить
                • > И запретить наследовать class от struct, ибо нехрен.
                  зря, динамитор таки нужен
                  Ответить
                  • А зачем в нем наследование непода от пода? В твоем динамиторе же наичистейшая аггрегация - он содержит в себе индикатор текущего типа и union с теми типами, что в нем могут храниться.

                    Или я не так понял твою идею?
                    Ответить
                    • Ну так динамировать можно поды.
                      И после динамирования они становятся неподами.
                      Ответить
                      • Ну так динамируют их аггрегацией, а не наследованием?
                        Ответить
                        • А какая разница, кроме синтаксической?
                          Ответить
      • > У меня 96.8% классов таких.
        И в 146% из них вообще не написаны деструкторы, т.к. дефолтная реализация вполне устраивает ;)
        Ответить
    • > кoнcтpyктop бeз мoдификaтopa virtual paбoтaeт тaк жe, кaк виpтyaльный дecтpyктop

      Это полный бред. При конструировании компилятор точно знает, какой тип конструируется, и может правильно сгенерировать код инициализации. Деструктор же может вызваться непонятно где на объекте неизвестного компилятору класса (есть только указатель на базу), компилятор не может правильно уничтожить иерархию без поддержки рантайма.

      Если не уничтожать объекты по указателям на базу (например, всегда аллоцировать их на стеке), механизмы конструирования и деконструкции корректны и симметричны.
      Ответить
    • Конструтор не виртуальный, ведь ты явно указал, какой именно конструктор тебе нужен.
      Более того, в крестах конструктор не бывает виртуальным хихи
      Ответить
    • ОК, следите за логикой.
      1) Если не объявить деструктор виртуальным, вызовется деструктор только базового класса.
      2) Есои обьявить его виртуальным, последовательновызовуться все леструкторы предков этого класса.
      3) Конструктор работает так же, как виртуальный леструктор - вызываются все конструкторы предков.
      Вопрос: нафига козе баян - нафиг описывать деструктор как virtual, если по другому и не над чтоб он работал?пс пишу с тела, сори за ошибки.
      Ответить
      • > Если не объявить деструктор виртуальным, вызовется деструктор толко базового класса.

        Правда чтоли?
        http://ideone.com/58KClV
        Ответить
        • Не знаю что там за компилятор... Проверил только что свой код на gcc и vc - без virtual вызывается только деструктор Base.
          Ответить
          • > Не знаю что там за компилятор...
            GCC 4.8.1, там как раз всё по стандарту. Аналогичный результат был бы на Borland C++ девяностых годов.

            > вызывается только деструктор Base
            Может всё же попробовать понять разницу между разрушением объекта известного типа и удалением указателя на базовый класс?
            Ответить
            • как у тебя только терпения хватает
              завидую твоему свободному времени
              Ответить
              • это борманд у нас чемпион...
                Ответить
              • Роман пишет, Дефекейт читает, Борманд и пишет и читает ... а мне, порой, даже читать влом.
                Ответить
                • Борманд играется в dark souls, борманду не до обсуждения виртуальных деструкторов ;)

                  P.S. Да и Тарас с Романом вполне справляются ;)
                  Ответить
                  • Грибы убивали?
                    Ответить
                    • Это которые прогуливаются во второй половине dark root garden?

                      Я в том районе совсем недолго был - поднялся со стороны озера с гидрой, увидел что-то похожее на ходячий гриб, хотел разглядеть поближе, и тут из-за деревьев выбежал большой кошак...

                      Так что с грибами пообщаться пока не довелось.
                      Ответить
                      • http://i.minus.com/ibc2txIiIfm9wT.gif
                        https://www.youtube.com/watch?v=jWkPpTv1vXk
                        Ответить
                    • Посмотрел на грибы, неплохо бьют - с поднятым щитом снимают всю стамину и все хп... Но вот от лука их это не спасло ;)

                      P.S. Волка жалко ;(
                      Ответить
          • Ты понимаешь вообще разницу между виртуальным и невиртуальным методом?
            Ответить
        • да можно и без виртуального деструктора и с указателем на базовый :)
          http://ideone.com/zGxwzm
          Ответить
      • >пс пишу с тела, сори за ошибки
        за логические?
        Ответить

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