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

    −16

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    MyBeautifulMarvelousStruc funcWithoutReturnStatement(FuckMyLife eatShitAndDie)
    {
        MyBeautifulMarvelousStruc mbms;
        mbms.myLife = eatShitAndDie;
    }
    
    int main()
    {
        ...
        MyBeautifulMarvelousStruc test = funcWithoutReturnStatement(eatShitAndDie);
        ...
    }

    Призываю дядь в крестах шарящих.
    Я объявляю функцию, возвращающую некую структуру. В определении не пишу "return". Собираю с MinGW 4.9.2 32bit. Собираю не вручную, подключил компилер в QtCreator-е. Ошибок при компиляции нет. Создаётся структура, поля которой есть неинициализированный хлам (что не удивительно). Вопросы:
    * Что возвращает функция без "return" в теле функции?
    * Почему это компилится?
    * Что читать, чтобы такие вещи знать?
    Не буду утверждать, что читал от корки до корки книжку дядюшки Шилдта, пользовался ей как справочник по базовому синтаксису с комментариями. Листал, короче.
    Или это разговор не о c++, а о компиляторах c++?

    Запостил: PascalOverlord, 27 Января 2017

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

    • > Почему это компилится?
      потому что компилятор так захотел, ворнинг то он все равно высрал
      что возвратит функция даже сам страуструп не сможет сказать, ибо это UB
      чтобы компилятор подавился, а не проглотил это говно, можно ему указать -Werror=return-type
      Ответить
      • UB?
        Ответить
        • undefined behavior, веселая штука
          Ответить
        • UB - это способ, которым достигается кросс-платформа на компилируемом языке, который сам по себе не кросс.

          Кароче, если че-та не описано четка в стандарте - это UB. На усмотрение разраба компилера/ОС/черта. Бывают случаи, когда пашет на винде годами, и сразу отказывается компилится на линухе ГЦЦ и прочее. Если тебя не интересуют конкретные извраты, а хочется четкой проверки - включаешь флаг компилера "все варнинги = ошибка" (см. инструкцию компилера).
          Ответить
          • > Кароче, если че-та не описано четка в стандарте - это UB. На усмотрение разраба компилера/ОС/черта.
            Это имплементейшон дефайнд. А UB - это невалидный код, бессмыслица (например разыменование невалидного указателя).
            Ответить
          • > Бывают случаи, когда пашет на винде годами, и сразу отказывается компилится на линухе ГЦЦ и прочее.
            Это просто баги реализации стандарта в студии или гцц. UB возникает в рантайме, а не во время компиляции.
            Ответить
      • > -Werror=return-type
        Только -Wall -Wextra, только хардкор.
        Ответить
        • -Wpedantic ещё, не?
          Ответить
          • Ну -pedantic и -std это скорее о следовании конкретному стандарту, чем о проблемах в коде... Но тоже можно.
            Ответить
        • у меня так в одном проекте - везде -Werror -Wall, но в одном модуле около 6 -Wno-*, потому что старый код в стиле "си с классами" не поддается компиляции без ворнингов...
          Ответить
          • Жиза. Разжаловать бы до стажеров всех этих С/С++ программистов.
            Ответить
            • Шиза. Разжаловать бы до вокзальных защеканов всех таких С/С++ программистов как ты.
              Ответить
            • показать все, что скрытода не, просто надо хорошо понимать си и с++ чтобы писать хороший код и там, и там, если доводится. А если что-то хорошо понимаешь, обычно ждешь хорошего оклада
              Ответить
              • Ждешь-ждешь, а его все нет и нет.
                Ответить
                • расскажи нам как тебе мало платят
                  Ответить
                  • Два доширака в месяц и двойной чизбургер по праздникам.
                    Ответить
                    • Завидуешь Antervisу?
                      Ответить
                      • Нет, он же пишет на кутэ.
                        Ответить
                        • а ты на чем пишешь?
                          Ответить
                          • C++ % C
                            Ответить
                          • На модерн си плюс плюс.
                            Ответить
                            • Лол) Крестовики презирают кутешников считая их "ненастоящими плюсовиками"?
                              Ответить
                              • Мне просто кутэ не нравится. Где ты прочитал презрение?
                                Ответить
                                • Оно сквозит. Я постоянно слышу: "да он(а) не на С++ пишет, а на куте"
                                  Ответить
                                  • > да он(а) не на С++ пишет, а на куте

                                    Ну технически это верно: Qt это не стандартный C++ и требует moc-компилятора.
                                    Ответить
                                    • а эти их функции (коннект? или как там) до сих пор хуево дружат с проверкой типов аргументов и перегрузкой?
                                      Ответить
                                  • > не на С++ пишет
                                    В моем комментарии не было. Ты нафантазировал, не вижу смысла это дальше обсуждать.
                                    Ответить
                                    • Даже не так. Во фразе "он(а) не на С++ пишет, а на куте" тоже нет презрения. Ты нафантазировал, не вижу смысла это дальше обсуждать.
                                      Ответить
    • >>Что возвращает функция без "return" в теле функции?
      Всякий мусор. Зависит от колконвеншена. Это UB, так делать никогда нельзя.

      >>Почему это компилится?
      Так написано в стандарте

      >>Что читать, чтобы такие вещи знать?
      Стандарт
      Ответить
      • Всё так, но ему будет сложно накопать инфу

        Студент, гугли про calling convention (уж про регистры, стек, кучу ты должен в своем возрасте знать), узнай какой используется в выбранном тобой языке (/компиляторе/декларации конкретной функции), поймешь где лежат данные, которые интерпретируются вызывающим как результат интересующей тебя функции - источник мусора можно определить уже с высокой точностью

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

        В итоге же полный и четкий ответ даст ассемблерный листинг твоей программы и конкретно куска, где был вызов. Есть даже инструменты онлайн - gcc.godbolt.org. В любом случае этот мусор вполне детерминирован, т.к. процессор не может сам нагенерить тебе мусор, он слишком бездушный ублюдок, он просто исполняет то, что ему дают.
        Ответить
        • Ага, без ассемблерного выхлопа никак. Если целый питух возвращается в основном аккумуляторе процессора (AX/EAX/RAX в x86), то плавающий может возвращаться в стеке сопроцессора, а с нескалярными значениями вообще всё сложно.
          Ответить
        • "- хочешь начать изучение С++?
          - Ага...
          - Это неправильный hello world, чтобы написать правильно иди кури стандарт, учи асм и выхлоп компиляторов..."

          > В любом случае этот мусор вполне детерминирован
          Так можно и в стекфрейм после другого приложения залезть
          Ответить
          • > после другого приложения
            Э, как?
            Ответить
            • ну, другая приложуха чуть больше памяти стека использовала, а ты в своих вызовах обращаешься к стеку дальше, чем выделяешь
              Ответить
              • На какой ОС можно залезть в адресное пространство другого процесса, прочитав свою память? О_о
                Или я дальтоник и не увидел зелёный?
                Ответить
                • VxWorks
                  Ответить
                  • Все задачи системы и приложения в VxWorks используют одно адресное пространство, что может привести к нарушению стабильности работы системы в случае неисправности какого-либо приложения.

                    Я думал, что такое только в DOS бывает...
                    Ответить
                    • > Все задачи системы и приложения
                      Назвали бы тредами, и никто бы не докопался :)
                      Ответить
                      • Там "таски", а не анскилльные процессы или треды. А ещё там можно прямо в сосноли сишные функции дёргать.
                        Ответить
                    • Наверное во всяких эмбедед системах тоже. Кто же туда мму завезет.
                      Ответить
                      • > VxWorks is a real-time operating system (RTOS) that can be used in embedded systems.
                        В самую писечку угадал.
                        Ответить
                  • UnlimitedVxWorks
                    Ответить
                • >> после другого приложения залезть
                  Было приложение, отработало, ракрылось. Память никто не занулял. Потом приходит второе приложение, садится на тот же стек и не найдя ни мобильного устройства, ни инструкции к туалетной бумаге, начинает смотреть на то, что высрало после себя уже завершившееся приложение.
                  Ответить
                  • Уважающие себя оси чистят страницы за отработавшими приложениями. Вилкой.
                    Ответить
                  • Гость выше правильно говорит. Такой хуйни нигде нет.
                    Ответить
                    • Везде проверял?
                      Ответить
                      • ну да, конечно, я засрал страниц на 10 гигабайт и сдох
                        и ось сразу метнулась тушканчиком их всех занулять
                        Ответить
                      • Только в линаксе. Все остальное ненужно.
                        Ответить
                        • надо же, не написдел

                          Memory from the heap is returned back to the system when it is unmap'd or the heap shrinks with sbrk(). At this point pages can be re-used by other processes and when they are re-used they are always zero'd before the process can access it.

                          Молодец какой!

                          Руссинович грит и винда не без этого:
                          "Firstly, the zero page thread runs at the lowest priority and is responsible for zeroing out free pages before moving them to the zeroed page list."
                          Ответить
                          • Да ясен хуй не без этого. Еще не хватало, чтобы левые процессы могли чужие пароли читать.
                            Хочу заметить, что память зануляется не после того, как страница возвращается системе, а перед тем, как система отдает страницу процессу.
                            Ответить
                            • Во-первых пароли надо занулять вручную. Вот тупо ZeroMemory же, иначе к тебе дебагером подцепятся или дамп снимут.

                              Во-вторых логично что эта штучка лениво работает: зачем заранее зануляться, если эта память никогда не понадобится?
                              Ответить
                              • > пароли надо занулять вручную
                                Особенно когда sigkill прилетает.

                                > Во-вторых
                                То была ремарка к твоему саркастичному комментарию "и ось сразу метнулась тушканчиком...".
                                Ответить
                                • >>Особенно когда sigkill прилетает.
                                  да, аргумент.

                                  >>То была ремарка к твоему саркастичному комментарию
                                  Я уже понял что обос^W^Wзаблуждался.
                                  Ответить
                          • то есть я попрошу у системы гигов 10 оперативки, а она будет ждать пока лоу-приорити тред занулит все страницы?
                            Ответить
                            • Не знаю, как в винде, а в линаксе, когда ты просишь у системы гигов 10 памяти, ты получаешь гигов 10 виртуальной и 0 физической. Физическая память аллоцируется лениво - только при первом обращении процесса к странице виртуальной памяти она мапится в страницу физической памяти. Если венду не идиоты писали, то при аллокации страницы она посмотрит в список зануленных страниц, и если там пусто, то возьмет страницу с мусором и сама занулит. Думаю, этот зануляющий поток - небольшая оптимизация, чтобы уменьшить время аллокации страницы.
                              Ответить
                              • Где-то я слышал, что у линухи вообще один r/o zero page на всех. И именно его ядро тебе отдаёт, когда ты пытаешься выделить странички. А если ты надумаешь туда писать - ядро подменит его на свежую страницу.

                                Вот только х.з., есть ли там тред для зануления или зануление будет только во время copy-on-write...
                                Ответить
                                • Кстати, а для чего нужен зоопарк, состоящий из hoard, jemalloc, tcmalloc, dmalloc, ptmalloc, nedmalloc, rtmalloc и прочих молок?
                                  Ответить
                                  • Больше молоков хороших и разных
                                    Ответить
                                  • Вероятно чтобы отыскать Лучший Алгоритм для аллокации, который бы:
                                    1) сводил к минимуму фрагментацию памяти
                                    2) работал бы ОЧЕ быстро
                                    Ответить
                                  • Видимо потому что один маллок для разных задач не подходит. Например, маллок из глибси неперфомансный и плохо работает в многопоточных программах (типа там глобальный мьютекс). Поэтому гугл изобрел tcmalloc, а фейсбук подхватил разработку jemalloc'а.
                                    Ответить
                                    • да там много всяких поводов

                                      например, free не возвращает сразу память системе чтобы не дерагать лишний раз сискол (sbrk или как там оно в линуксе).

                                      Ребят уровня фейсбука и гугла это может не устраивать
                                      Ответить
                                • > Вот только х.з., есть ли там тред для зануления или зануление будет только во время copy-on-write...

                                  IIRC, во время COW (copy-on-write). смысла мало обнулять физ память которая может быть и не будет использоватся для памяти приложений. на линухе файло-диско-кэш резиновый, и потребляет часто больше памяти чем приложения.

                                  > что у линухи вообще один r/o zero page на всех.

                                  ага. /dev/zero из этой же странички данные и читает. неиссякаемый источник нулей...
                                  Ответить
                              • в винде тоже так, Только терминология уебищная
                                WorkingSet это память в RAM, ЕМНИП, а вся вместе называтеся VIRTUAL
                                Ответить
        • >> Создаётся структура, поля которой есть неинициализированный хлам (что не удивительно).
          >> * Что возвращает функция без "return" в теле функции?
          >> * Почему это компилится?
          > гугли про calling convention
          > источник мусора можно определить уже с высокой точностью
          А мне кажется, вопрос был не про сорта мусора, а про идеологию; что автору поста как-то пофиг на конкретные байты, в которых, разумеется, что-то несвежее осталось.

          * Какого хрена компилятор в языке с якобы строгой типизацией не бугуртит ошибками на такое разгильдяйство?
          * Если это компилируется, то какая суть у возвращаемого значения? (JS без return возвращает значение специального типа)
          Ну по крайней мере, я бы такие вопросы задал, если бы мне было не лень создавать новый пост.
          Ответить
          • Тут вопрос только в том, какого хрена ворнинг по-умолчанию не включен.

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

              Предвосхищая вопрос "причём тут строгая типизация?", напишу:
              Возвращается значение определённого типа, поэтому и строгая типизация.
              Иными словами, неявный каст void в произвольный тип - питушня, противоречащая идеологии строгой типизации.
              Ответить
              • В декларейшене прописано что возвращается, и переменная этого же типа. Всё честно.
                А что там внутри функции делают комплеятор знать не обязан.

                А вот что в дефишинеше написано что надо что-то вернуть, а возвращают ничего -- это фейл, но типизация тут не причемю
                Ответить
                • > причемю
                  Охуенно, форсим поцаны!
                  Ответить
                • >> неявный каст void в произвольный тип
                  > не причемю
                  Ответить
                  • Все еще непричемю.
                    В каком месте там каст?
                    Ответить
                    • Это же неявный каст, он там, где компилятор скажет.
                      Ответить
                      • давай не будем путать жареное с летним. По стандарту, это UB, и программа не является корректной, т.е. компилятор не обязан её жрать. А то, какого лешего компилятор её пропускает - хз, наверно "исторически так сложилось".
                        Ответить
                        • Если, например, конструктор MyBeautifulMarvelousStruc всегда кидает исключение, то не уб и код корректен.
                          Ответить
                          • если возвращаемое значение функции используется (throw/std::exit/пр. такого не позволят), и оно не было возвращено через return - это ub.
                            Ответить
          • > * Какого хрена компилятор в языке с якобы строгой типизацией не бугуртит ошибками на такое разгильдяйство?

            Жрет кактус, срет ворнингами. Это наследие си просто
            Ответить
            • Имхо, не столько си, сколько совсем тупых конпеляторов, которые даже в простых случаях не могли задетектить недостижимый код... А лишний return писать не хотелось.
              Ответить
    • показать все, что скрытоTechnical post. RSS fixed.
      Ответить
    • ->от корки до корки книжку дядюшки Шилдта
      Он в своей книге излагает, скорее всего как тётушка
      Ответить
    • #охужэтонаследиеси
      Ответить
    • показать все, что скрытоМой Watcom отказывается это компилировать!
      Ответить
      • Откомпилировал твой watcom своим open64, проверь.
        Ответить
      • Откомпилировал Watcom'ом, проверь:

        typedef struct {int myLife;} MyBeautifulMarvelousStruc;
        typedef int FuckMyLife;
        
        MyBeautifulMarvelousStruc funcWithoutReturnStatement(FuckMyLife eatShitAndDie)
        {
            MyBeautifulMarvelousStruc mbms;
            mbms.myLife = eatShitAndDie;
        }
        
        FuckMyLife eatShitAndDie;
        
        int main()
        {
            MyBeautifulMarvelousStruc test = funcWithoutReturnStatement(eatShitAndDie);
        }


        Кстати, у Watcom'а есть удобная директива #pragma aux, в которой можно явно указать, кто будет выделять память под возвращаемую структуру: вызывающий код или вызываемая функция.
        Ответить
        • а разве это не является частью соглашения вызова?
          Ответить
          • Является. Но там с помощью прагмы можно создавать новые соглашения, чтобы раскидать побольше граблей.
            Ответить
            • > создавать новые соглашения
              Т.е. можно совсем другое соглашение описать - набор регистров и т.п.? Или только немножко подтюнить стандартные?
              Ответить
              • Да. И регистры (включая сопроцессор), и порядок заталкивания аргументов, и кто чистит, и маппинг внешних имён, и некоторые особенности, которые помогают оптимизатору. Есть прагмы для встроенного ассемблера с описанием регистров (типа как в gcc).

                Более того, стандартные соглашения тоже где-то описаны:
                #pragma aux __syscall "*" \
                    parm caller [] \
                    value struct struct caller [] \
                    modify [eax ecx edx]
                #pragma aux __stdcall "_*@nnn" \
                    parm routine [] \
                    value struct struct caller [] \
                    modify [eax ecx edx]
                #pragma aux __pascal "^" \
                    parm reverse routine [] \
                    value struct float struct caller [] \
                    modify [eax ebx ecx edx]
                #pragma aux __cdecl "_*" \
                    parm caller [] \
                    value struct float struct routine [eax] \
                    modify [eax ecx edx]


                Кстати:
                The following form of the auxiliary pragma can be used to describe a function that does not return to the
                caller.


                #pragma aux sym aborts
                Ответить
            • а чем их "пусть компилятор сам оптимизирует как хочет, лишь бы весь публичный апи был на стандартных конвенциях" не устроило?
              Ответить
              • Наверное потому что ватноком сделали во времена, когда делать мощные оптимизаторы еще не умели.
                Ответить
                • показать все, что скрытоОптимизровал тебе за щеку, проверь
                  Ответить
                • > ватноком

                  Мне нравится. Будем форсить?
                  Ответить
                  • Да он сдох давно, чего там форсить.
                    Ответить
                    • ты не осилил шутку, лол
                      Ответить
                    • http://perforce.openwatcom.org:4000/@md=d&cd=//depot/openwatcom/&c=Duk@//depot/openwatcom/?ac=43

                      4 января сего года был коммит.

                      Ватноком — тёплый, ватный, белый. Проверь.
                      Ответить
                      • P.S. Яундекс нашёл только одно упоминание Ватнокома, да и то это оказалось опечаткой. Гаугля нашла четыре упоминания, но тоже все оказались опечаткой.

                        У нас есть реальный шанс зафорсить что-то новое.
                        Ответить
                      • pervert.openwatcom.org
                        Теплый, ламповый, твой *

                        -----------------------
                        * Поддержка стандартов C++17 и C11 заблокирована по решению органов государственной власти.
                        Ответить
                        • Скачать можно с BBSки. Работает почти все время, кроме ночи.

                          Maintenance time is being implemented to allow for development and testing. The server will be offline during the following hours:
                          Day	USA	Day	Europe
                          Sun - Fri	11 PM CST - 2 AM CST	Mon - Sat	6 AM CET - 9 AM CET
                          Sat	11 PM CST - 5 AM CST	Sun	6 AM CET - 12 PM CET

                          Ночью просто маме телефон нужен..
                          Ответить
                        • > Поддержка стандартов C++17 и C11 заблокирована

                          Внезапно:
                          https://en.wikipedia.org/wiki/C11_(C_standard_revision)#Criticism

                          The open-source Open Watcom C/C++ contains a "Safer C" library that is considered a nearly conforming implementation.

                          Т. е. ко-ко-конпелятор C11 не поддерживает, но библиотека на всякий пожарный с C11 совместима.
                          Ответить
                      • Паулу делать нехя просто
                        Ответить
                        • Он как настоящий ватнок верит в будущее проекта Нововаткомия, поэтому в одиночку борется со студомитами, интелогами, шланганутыми и гэцэцэсовцами.
                          Ответить
              • Царь лучше знает, какое соглашение оптимальнее. Кстати, специально для остроконечников и тупоконечников у них две стандартные библиотеки: одна скомпилирована с регистровым соглашением, другая со стековым. Царь может выбрать ту, которая на его процессоре даёт больший пирфоманс.
                Ответить
                • Царь лучше знает, какое разъёбывание очка оптимальнее. Кстати, специально для остроконечников и тупоконечников у них две стандартные смазки: одна с красным перцем, другая с ацетоном. Царь может выбрать ту, которая на его процессоре даёт больший пирфоманс.
                  Ответить
    • показать все, что скрытоMinGW не нужен
      Ответить
    • > Почему это компилится?

      напомнило о старой доброй проблемке (тьюринговских машин): а завершится ли программа, или нет?
      Ответить
      • Нет, это не такая сложная проблема. Компилятор знает все точки выхода из функции (он туда деструкторы вставляет). Достаточно потребовать, чтобы пользователь писал в этих точках return. То что си(++) этого не требует - проеб.
        Ответить
        • ёжику понятно что проёб. но даже в пасцале это было проблемой: забыл результат присвоить, и то же самое UB-ище что и здесь.

          с другой стороны, все компилеры поддерживают варнинги для этого. я уже давно без -Wall ничего не компилю. (правда на крестах всегда отключаю -Wreorder потому что это маразм.)
          Ответить
          • Почему маразм? Правильный порядок полей в списке инициализации помогает случайно не заиспользовать неинициализированное поле при инициализации другого поля. Хотя конечно вероятность прострелить себе ногу всегда есть.
            Ответить
            • зависимость от порядка инициализации - "defective by design".
              Ответить
              • см. ниже
                Ответить
              • Почему? Если одно поле работает с другим полем, то как тогда делать?
                class Bormand {
                    io_service my;
                    ssl::context waifu;
                    ssl::stream<ip::tcp::socket> kawaiii;
                
                public:
                    Bormand() : waifu(ssl::context::sslv23), kawaiii(my, waifu) {}
                };
                Ответить
                • Тот самый пример ссылкоёбства, про который ниже писал Dummy00001. Тебя заставили вручную контролить время жизни объектов (my и waifu обязаны жить дольше чем kawaii, иначе UB), а ты радуешься... Зато пирфоманс, да.
                  Ответить
                  • Причем тут время жизни? Тут граф зависимостей такой. Если бы там были шаредпойнтеры, ничего бы не изменилось. Сначала надо создать иосервис и контекст, а потом стрим.
                    Ответить
                    • При том, что ssl::stream заставляет меня менеджить ссылку на ssl::context (которая мне нахуй не нужна). shared_ptr я бы скормил ему и забыл, пусть сам с ним разбирается. А эту сраную ссылку мне теперь вечно с собой таскать. И не дай бог она сдохнет раньше.
                      Ответить
                      • Я понимаю твое недовольство необходимостью управлять лайфтаймами, но мне придется повторить вопрос.

                        > Причем тут время жизни?
                        > Если бы там были шаредпойнтеры, ничего бы не изменилось.
                        > Сначала надо создать иосервис и контекст, а потом стрим.
                        Ответить
                        • > причём тут время жизни
                          В этом конкретном примере тебе просто повезло, что всех объектов по одной штуке. Но обычно сокетов много, а иосервис - один на всех. Да и ssl::context реюзабельный. И вот там управление лайфтаймом ссылок уже не так тривиально (кроме, пожалуй, "засуну их все в глобалки, да и хуй с ними").

                          > ничего бы не изменилось
                          > сначала надо создать иосервис и контекст, а потом стрим
                          Если бы там были шаред поинтеры - я бы мог запилить всё это по-отдельности внутри конструктора (или взять уже готовые). Ссылки заставляют меня делать всё это в инициализаторе. Ссылки заставляют меня тащить зависимости в инициализатор (ну кроме совсем-совсем глобальных). У меня нет выбора. Я обязан иметь все необходимые объекты к моменту вызова инициализатора.
                          Ответить
                • > Почему? Если одно поле работает с другим полем, то как тогда делать?

                  самое простое & straightforward решение - динамика:

                  class Bormand {
                      io_service *moe;
                      ssl::context *waifu;
                      typedef ssl::stream<ip::tcp::socket> chomechome;
                      chomechome *kawaiii;
                  
                  public:
                      Bormand()
                      {
                          this->moe = new moe;
                          this->waifu = new ssl::context(ssl::context::sslv23);
                          this->kawaiii = new chomechome(moe, waifu);
                      }
                  };


                  или, если жмет, тогда как ты делал + ревью.
                  Ответить
                  • > io_service *moe;
                    > this->moe = new moe;
                    Фублядь, фунахуй! Этот код же течёт как сучка весной... Такое я бы на ревью точно не пропустил (хоть у нас и нету исключений, лол).
                    Ответить
                    • ... в легких кторах нечему бросать исключений.

                      PS с другой стороны, запихиваешь это в `bool Bormand::Init()` и все пучком. так или иначе ошибки конструкции/инициализации обрабатываеть надо. я предпочитаю их явно и без исключений получать.
                      Ответить
                    • А че ты доебался? Он же деструктор в этом примере явно опустил для простоты. Не для продакшена же
                      Ответить
                      • Сема зайди с другого аккаунта. А то еще подумают, что я тупой.
                        Ответить
                        • Что не так я написал?

                          P.s. на крестах не пишу
                          Ответить
                          • Там проблема в исключениях, которые могут вылетать из каждой строчки, и из-за которых все уже аллоцированные поля утекут.
                            Ответить
                            • Если вторая строка кинет исключение, то память первой никто не почистит?
                              Какой тогда выход?
                              1) не использовать new
                              2) не использовать конструкторы
                              3) на один new одна обертка?
                              Ответить
                              • > на один new одна обертка
                                Ответить
                              • Там парой сообщений ниже уже написал, но продублирую: использовать магию RAII, а именно, смартпойнтеры. Это вариант 1) у тебя.
                                Ответить
                                • > Это вариант 1) у тебя.
                                  Смартпоинтеры - это вариант 3 (на один new одна обёртка), тащемта.
                                  Ответить
                                  • Может он имел в виду обертку try{}catch(){}.
                                    Ответить
                                    • Под оберткой я имел в виду класс, где в конструкторе только 1 new
                                      Ответить
                                      • Ну типа того. Только не надо писать отдельный класс для каждого указателя.
                                        Ответить
                                        • его за тебя напишет кококонпелятор.
                                          Ответить
                              • std::make_unique
                                Ответить
                      • > деструктор
                        Как-будто его кто-то позовёт...
                        Ответить
                  • Лол. Ну-ну.
                    Ответить
                  • Кстати, популярное задание на скайп-собеседовании в яндексе - сделать этот конструктор exception-safe.
                    Ответить
                    • это возможно? я так до сих пор и не уверен что это возможно. флеймы что можно видел - но все примеры которые приводили были тоже дырявыми.

                      я стараюсь делать легкие кторы + bool Init() методы. потому что из ктора значения вернуть нельзя. и не виртуальный он. а с обычным методом инициализации можно делать все что хочешь.
                      Ответить
                      • Канонiчный способ - переделать на смартпойнтеры. Если напишешь портянку из try-catch, то на очку не позовут.
                        Ответить
                      • > я так до сих пор и не уверен что это возможно.

                        А ты уверен, что понимаешь семантику конструирования объектов? Знаешь, что происходит с первым сконструированным "полем", если конструктор второго "поля" кидает исключение?

                        Честно говоря, меня очень удивляет, что С++-погромисты не знают таких вещей. Конструкторы и деструкторы — cамая полезная фича языка, и 95% погромистов не знает, как этим пользоваться.
                        Ответить
                        • я на столько давно крестами пользуюсь, что честно говоря я знаю только одно: я ничего не знаю.

                          о, нет, знаю: на кресты и их компилеры полагатся ни в чем нельзя. (как и на десктопных макак которые компилеры раз в неделю меняют.)

                          буду рад если просветишь, потому что на стандарт все равно забил, и самый свежий компилер под рукой это гцц 4.8.
                          Ответить
                          • > буду рад если просветишь

                            Если в конструкторе по какой-либо причине происходит исключение, всё уже сконструированные поля автоматически разрушается в порядке обратном тому, в котором они были сконструированы. Деструктор конструируемого объекта при этом, понятное дело, не вызывается. Это позволяет писать простой, понятный и корректный код без портянок try/catch. Поэтому порядок членов в классе и инициализаторов в конструкторе важен.

                            Всё это работало ещё в сраном сfront-е и никогда не изменится — это суть языка. Почитай Inside the C++ Object Model на досуге, на редкость занимательная книжица.
                            Ответить
                            • "Если в конструкторе по какой-либо причине происходит исключение, всё уже сконструированные поля автоматически разрушается в порядке обратном тому, в котором они были сконструированы."

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

                              ЗЫ о. ты мне напомнил. видел еще грабли когда конпилер порядок инициализации полей менял. вставляешь в конструкторы принтфы - работает как надо. удаляешь принтфы - криво. но это очень древняя история со времен гцц 2.95/билдер 5.5/vc++6.
                              Ответить
                              • > что это не всегда/не везде работает

                                Обжёгся на молоке, дует и на воду.

                                На твоём компиляторе не работает? Указатели тоже на nullptr проверяешь перед тем, как удалить? А результат оператора new?
                                Ответить
                                • "Обжёгся на молоке, дует и на воду."

                                  Ты пословицу изкаверкал. "Раз молоком обжёгся - на воду дуешь". 10+ лет работы с недоделаными компилерами - включая и текущий момент - это не "раз".

                                  Я бы рад новыми компилерами пользоватся - компилерами на которые можно полагатся - но гамно на текущем проекте даже темплейтов не умеет (IAR 5.10/5.50).
                                  Ответить
                                  • Ничоси.
                                    Ответить
                                    • на самом деле это конечно исключение. но с другой стороны, все тутошние разговоры просто напоминают о том какая у людей короткая память.

                                      с точки зрения gcc, 3.х слегка сосали. 4.х, С++03 и частично С++11, где-то только в 2008-10 году стабилизировались. 5.1 вышел в 2015 и был первым гцц где С++11 был официально полноценно поддержан.

                                      а народ тут повествует как если бы щасце неглючных компилеров наступило вечность назад.
                                      Ответить
                                      • У меня память не короткая, просто я младше тебя лет на 20.
                                        Ответить
                                      • > С++03 и частично С++11, где-то только в 2008-10

                                        То, о чём я говорю, относится к стандарту 98 года.
                                        Ответить
                                        • > То, о чём я говорю, относится к стандарту 98 года.

                                          ... который только до конца в 2003 допилили.

                                          но какая в ж разница какой год если ни в 98 ни в '03 не было ни одного компайлера который 100% этого стандарта не умел.
                                          Ответить
                                  • > гамно на текущем проекте даже темплейтов не умеет

                                    Так бы и сказал, что у тебя не С++, а си с классами, и компилятор, не поддерживающий даже стандарт 98 года.

                                    То, что когда-то компиляторы были плохими, не означает того, что не нужно знать базовую семантику языка, на котором пишешь.
                                    Ответить
                                  • > гамно на текущем проекте даже темплейтов не умеет
                                    Держите плюсик. Я бы кружечку горячего чаю/какао вам налил в знак соболезнования.
                                    Ответить
                                    • Неймспейсы умеет?
                                      Ответить
                                    • Может он за это получает пять твоих годовых зарплат в месяц, а ты соболезнуешь.
                                      Ответить
                                • > результат new
                                  Если оно nothrow - куда деваться...
                                  Ответить
                                • > Указатели тоже на nullptr проверяешь перед тем, как удалить? А результат оператора new?

                                  ну не надо о больном то...
                                  Ответить
                              • потому что деструктор сырого указателя не вызывает delete на управляемый объект...

                                ЗЫЫ вообще, в языке есть всего две оптимизации, позволяющие менять наблюдаемое поведение: RVO и copy elision. А "вставил printf - заработало" - это обычно не в компиляторе дело, а какой-то метод стек портит (возможно, из-за некорректных соглашений о вызовах)
                                Ответить
                                • > потому что деструктор сырого указателя не вызывает delete на управляемый объект...

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

                                  эффект принтфа был в том что он предотвращал инлайнинг конструкторов. без инлайнов - код генерился правильный. заинлайненый - кривой.
                                  Ответить
                      • > + bool Init() методы

                        assert(IsInitialized()) в каждый метод вставляешь?
                        Ответить
                        • нет. только иногда. ситуация ничем не отличается от вызова метода по кривому поинтеру (или по указателю на деконструированый объект).
                          Ответить
                          • Если что, это тоже UB, и проверку this на ноль компилятор выпилит.
                            Ответить
                            • ну те кто this на NULL проверяет, это отдельная порода.

                              с другой стороны, по личному опыту, эта проверка смысла мало имеет, потому что кривой this редко бывает NULL.
                              Ответить
                        • > assert(IsInitialized()) в каждый метод вставляешь
                          Да, приходится. Исключений не от хорошей жизни нету :(
                          Ответить
                        • Ещё вот такой вариант юзаем - можно этот вызов Init() в фабричный метод спрятать. Который либо возвращает ошибку, либо заполняет смартпоинтер валидным объектом.

                          Тут хотя бы джвухфазная инициализация скрыта от юзера. И невалидный объект не запилишь.
                          Ответить
                    • > сделать этот конструктор exception-safe
                      Сделал, проверь:
                      Bormand()
                      {
                          std::unique_ptr<io_service> moe_tmp(new moe);
                          std::unique_ptr<ssl::context> waifu_tmp(new ssl::context(ssl::context::sslv23));
                          std::unique_ptr<chomechome> kawaiii_tmp(new chomechome(moe, waifu));
                      
                          this->moe = moe_tmp.release();
                          this->waifu = waifu_tmp.release();
                          this->kawaiii = kawaiii_tmp.release();
                      }
                      Ответить
                      • Почему зелёным? Это хорошее, правильное решение же.
                        Ответить
                        • > правильное
                          Правильное, имхо, поля сделать смартпоинтерами...
                          Ответить
                          • > Правильное, имхо, поля сделать смартпоинтерами...

                            Это да, но не всегда возможно. На собесе обычно явно говорят, что члены класса менять нельзя.
                            Ответить
                            • А к решению в духе "заполнить нуллами, потом внутри трая создать объекты и в кетче убить не нуллы" как отнесутся? :3
                              Ответить
                              • > заполнить нуллами, потом внутри трая создать объекты и в кетче убить не нуллы" как отнесутся?

                                Нормально. Это одно из типовых решений.
                                Ответить
                                • а выделить память разом и размещать через placement new?
                                  Ответить
                                  • > размещать через placement new
                                    А если у этих объектов деструктор нетривиальный?
                                    Ответить
                                    • повторяем рекурсивно пока не упремся в pod'ы
                                      Ответить
                • > Bormand() : waifu(ssl::context::sslv23), kawaiii(my, waifu) {}
                  А теперь настрой мне waifu (добавь туда сертификатики CA, к примеру) перед конструированием kawaii.
                  Ответить
                  • > А теперь настрой мне waifu
                    waifu NastroyMneWaifu();
                    
                    Bormand::Bormand() : waifu(NastroyMneWaifu()), kawaiii(my, waifu) {}
                    Ответить
                    • Ага, а расшарить зависимость можно если хранить её в shared_ptr и отдавать как *my_ptr()...
                      Ответить
                      • А расшарить зависимость можно создав её в main (ну или просто выше по стеку) и передав в конструктор Bormand как параметр.
                        Ответить
                        • Ну в main - да. А в других местах, имхо, как-то боязно. Не люблю, когда жизнь объекта и его друзяшек не получается оценить по одному экрану кода...
                          Ответить
                        • З.Ы. Хотя, если везде следовать правилу "если дал объекту X не const ссылку на Y, то Y обязан пережить X" - вполне работает.
                          Ответить
                          • Почему только не const?
                            Ответить
                            • Потому что потом страшно будет методам давать поюзать const ссылку - вдруг они её заныкают?
                              Ответить
                              • Понял. Ну мне кажется, что так оно не сработает. Надо либо пологаться на документацию, либо сделать специальный класс обертку над ссылкой borrowed, если хочется по сигнатуре и вызову видеть, что ссылка останется в объекте.
                                А потом прикрутим боровчекер к шлангу, и будет у нас говнораст.
                                Ответить
                      • у меня коллега гениальную штуку сделал в одном проекте. Синглтон через статик weak_ptr. T::instance() -> std::shared_ptr<T>;
                        Ответить
                        • А если нулл получился - новый инстанс запиливает?
                          Ответить
                          • Угу
                            Ответить
                            • Прикольно, но не потокобезопасненько.
                              Ответить
                              • я, кстати, хз, что надо делать с shared_ptr чтобы словить косяк от непотокобезопасности
                                Ответить
                                • Джва потока зашли в T::instance(). Каждый посмотрел на закешированный указатель и получил nullptr. Каждый сконструировал себе по инстансу и засунул его в кеш.

                                  Теперь по коду гуляют джва инстанса "синглтона" (один из них скоро сдохнет, но не сразу).

                                  З.Ы. Или там какой-то дополнительный семафорчик есть, а не только weak_ptr?

                                  З.З.Ы. Всё, пора спать, дополнительный семафор там однозначно есть. Ибо сами shared_ptr и weak_ptr нельзя юзать из джвух потоков.
                                  Ответить
                                • Причём именно семафор, ибо std::weak_ptr не потокобезопасен (как и std::shared_ptr, впрочем) и атомиков для него нету.

                                  Ткни меня носом, если я не прав.
                                  Ответить
                                  • я вообще всегда думал, что счетчик там атомарный. Можно вот этим набором еще пользоваться: http://en.cppreference.com/w/cpp/memory/shared_ptr/atomic
                                    Ответить
                                    • Счетчик там атомарный. И разные шаред птр, ссылающиеся на один объект можно безопасно юзать из разных тредов.

                                      Но вот сам шаред птр не потокобезопасен. И в джва треда без лочки/атомиков с ним работать нельзя.

                                      А атомиков для weak я что-то не нашёл (только для шаред).
                                      Ответить
                                    • Нельзя без внешней блокировки менять объект, на который ссылается shared_ptr.

                                      История из жизни: ревьюил разок код, где хотели реализовать "горящее" обновление конфигурации процесса при получении SIGHUP. Конфиг положили в глобальный shared_ptr, который читался тредами-воркерами и время от времени перезаписывался новой версией асинхронно тредом, слушающим сигналы.

                                      Люди почему-то решили, что shared_ptr "потокобезопасный", и можно делать такие вещи без всяких мутексов. Так вот — нельзя. Можно безопасно копировать shared_ptr из разных потоков. А вот чтение в одном потоке объекта, который изменяется в другом без внешней блокировки — это точно такой же датарейс.
                                      Ответить
                                      • погоди секунду. Вот есть объект, и (например) он сам следит за своей потокобезопасностью. Его сунули в shared_ptr и используют в многопоточном окружении. Где грабли?
                                        Ответить
                                        • > Его сунули в shared_ptr и используют в многопоточном окружении. Где грабли?

                                          Здесь грабель нет. Грабли появляются, когда ты кладёшь новый объект в shared_ptr без мутекса.
                                          Ответить
          • > отключаю -Wreorder
            Глупо, имхо. Нафиг на ровном месте грабли раскладывать? Конпелятор же один хуй сделает по-своему (в порядке объявления полей, забив на порядок инициализаторов в конструкторе). А без этого ворнинга кто-нибудь рано или поздно не посмотрит на порядок членов в классе и обосрётся с конструктором.
            Ответить
            • грабли люди себе сами раскладывают - когда делают код зависящим от порядка инициализации.

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

              знаю что в крестах есть фанаты референсов, которые без этого просто жить не могут. но это те же самые идиоты которым либо лень один символ больше напечатать, либо наивно думают что так как нет '->' то код будет быстрее потому что нет дереференса.

              вообщем - маразм.
              Ответить
              • > когда делают код зависящим от порядка инициализации
                Я согласен. Но если кто-то по-неопытности (или по-необходимости) въебёт зависимость - лучше уж ворнинг, чем молчаливый UB.

                А ворнинга про "зависимость от порядка инициализации" то нету, надеешься всё это отбить на ревью?
                Ответить
                • > А ворнинга про "зависимость от порядка инициализации" то нету, надеешься всё это отбить на ревью?

                  да. архитектить/дезайнить компилеры все таки еще не умеют. ;)

                  я всегда пытаюсь кторы легкими делать. и по граблям зависимостей инициализации ходил - как и по граблям тормозных кторов. (у меня был как-то раз плачевный опыт когда объект ключа для хэша (доморощеного) создавался в среднем дольше чем вычесление ключи + поиск в самом хэше.)
                  Ответить
              • > фанаты референсов
                > идиоты

                Вот это предъявы. Обоснуй.

                > лень один символ больше напечатать, либо наивно думают что так как нет '->' то код будет быстрее

                Про то, что ссылки используют, потому что они безопаснее, ты не слышал конечно же?
                Ответить
                • > Про то, что ссылки используют, потому что они безопаснее, ты не слышал конечно же?

                  чем они безопастнее?

                  когда увижу хотя бы один проект где не будут из указателей референсы делать (и не будет `if (&ref != NULL)`) я может быть и поверю в это преславутую безопастность.
                  Ответить
                  • Сначала сами все инты по куче разложат, а потом ссылки на ноль проверяют.

                    Тут неоднократно обсуждали, что компилятор делает с такими if'ами (https://godbolt.org/g/2EHGbO).
                    Ответить
                    • > https://godbolt.org/g/2EHGbO

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

                      PS проверку дропает только начиная с гцц 6. в пятерке она еще генерится. где дискусия почему проверку дропают?
                      Ответить
                      • Тебе не кажется, что говно по дезайну - это код, в котором могут появляться нулевые ссылки?

                        > почему проверку дропают
                        Потому что ссылка не может быть нулевой. Ты ведь хороший программист и не разыменовывал нулевой указатель? Это UB!
                        Ответить
                      • так сама суть ссылки, смысл, который в неё заложен - указатель на РЕАЛЬНЫЙ объект
                        Ответить
              • > которым либо лень один символ больше напечатать

                А моя иде сама меняет . на -> даже когда не прошу блеать

                референс нужен в т.ч. для адекватной семантики копирования. В этом нет ничего зазорного
                Ответить
        • а если один компилятор видит что эта точка недостижима и ругается(варнингом) на недостижимый return, а более глупый не развернул константы, думает что она достижима и ругается если ретурна нет?
          Ответить
          • Ты о чем? Где я говорил про достижимость? Требовать оператор return надо во всех точках выхода из функции независимо от их достижимости.
            Ответить
            • Хотя такая точка только одна - конец тела функции. Остальные можно только искусственно создать как раз с помощью return.
              Ответить
            • if (_field)
                  return _field;
              else
                  return {};
              // Warning: missing return at the end of function, returning non-void
              Ответить
          • > один компилятор видит что эта точка недостижима
            > а более глупый не развернул константы, думает что она достижима
            Бывает и хуже: http://govnokod.ru/12472
            Ответить
            • Видел такую тему в плюсах с каким-то гцц. Не пишешь return после switch'а - ворнинг, что нет return'а. Пишешь return - ворнинг про недостижимый код.
              Ответить
              • старые версии этим грешили. в новых гцц просто варнинг расслабили + улучшили распознование control flow внутри функции. пофиксить не пофиксили - но уже в гцц 4.х этого варнинга я уже не видел.

                потому что в старые времена тупой главный цикл - int main() { while(1) {}; } - уже кидал этот ворнинг.
                Ответить
    • Вот читаю я этот тред и понимаю, что с Dummy00001 или бормандом нам было бы сложно работать вместе. Что вы делаете, когда убеждения или опыт коллег сильно расходятся с вашими и разногласия носят глобальный характер? Как справляться с такими рабочими ситуациями? У меня вот есть такие коллеги, и я просто тихо батхерчу и стараюсь лишний раз с ними по коду не пересекаться.
      Ответить
      • Искать компромисс, лол.

        З.Ы. ИРЛ я всё-таки не такой упоротый, как тут.
        Ответить
        • > Искать компромисс, лол.

          самые упортые на форумы не ходят. что бы компромисы искать - надо разговаривать. а если слишком долго разговаривать, то коллеги могут начать догадываться какой дебил. вообщем, коммуникация, как обычно.
          Ответить
      • Увольняться же.
        Ответить
        • Да сколькож можно увольняться.
          Ответить
          • А что, ни с кем не сработаться?
            Ответить
            • Да, как-то не получается.
              Ответить
              • Ну тогда нужно пытаться попасть в какую-нить серьезную компанию типа Гугла.
                Если окажется что и там никто не умеет программировать, то придется признать что все люди -- идиоты и тебя спасет только стартап.
                -----
                зы: я тоже иногда бугурчу. Мне кажется что все кругом пишут тупой бойлерплейт, да еще и не документированный. А должны писать тонкие и красивые фреймворки, которые сами будут решать все проблемы, а потом еще их документировать так, чтобы я прочитал гайд, и всё понял а не сидел в дебагере 8 часов
                Ответить
                • > дебаггер
                  Передай своим коллегам, что они анскиллы. Над тру интерпрайзом ты в дебаггере не посидишь -- хартбиты поедут и всё ребутнётся вместе с твоим дебаггером.
                  Ответить
                  • у меня и не интерпрайз сейчас)

                    на самом деле про дебагер это я конечно загнул. Иногда достаточно 8 часов почитать код и всё становится понятно.
                    Ответить
                • > не умеет программировать
                  Да тут скорее не "не умеет", а "программирует не так, как я".

                  У всех свои профдеформации, везде свои гайдлайны, да и специфика проекта порой ограничения накладывает.
                  Ответить
                  • Это какой-то умудренный опытом подход.

                    Молодой программист должен считать говнокодерами всех, кто программирует не так, как он.
                    Ответить
      • > Что вы делаете, когда убеждения или опыт коллег сильно расходятся с вашими
        - набраться харизмы и терпения
        - убедить всех, что они - тупые мудаки
        - постоянно тыкать их носом в насранное и возюкать, возюкать, как котят
        - конфликты игнорировать, уходить с работы вовремя, вкусно кушать и вволю спать
        - гуси, ответный звонок, это всё

        та спокойно нужно относиться
        все косячат, у всех какие-то тараканы; вполне возможно, более чем обоснованные
        Ответить
      • "Что вы делаете, когда убеждения или опыт коллег сильно расходятся с вашими и разногласия носят глобальный характер?"

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

        "Как справляться с такими рабочими ситуациями?"

        С друг другом разговарить. Учится у друг друга.

        Если не способен учится - либо садить в угол и давать ему ручные тесты делать, либо в начальники промотить.
        Ответить
        • Как не учиться так, чтобы запромоутили в начальники?
          Ответить
      • > Что вы делаете, когда убеждения или опыт коллег сильно расходятся с вашими и разногласия носят глобальный характер?

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

        не верю. но линуха под рукой потестировать нет. память для возващаемого объекта выделяется на стеке - и выделяется она всегда. отсутствие/присутствие return'а в С/С++ никогда проблемой не было, потому что calling convention не пасцалева.
        Ответить
        • Я тебе вчера показывал мощнейший инструмент https://godbolt.org/g/vRTjpe
          Ответить
        • Вот еще линукс, который всегда под рукой. Там есть и гцц, и шланг, и даже буст.
          http://coliru.stacked-crooked.com/a/5eacd8836d69a3dd
          http://coliru.stacked-crooked.com/a/88fa5a7c5df2f583
          Ответить
      • Ты обосрался.
        Ответить

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