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

    −17

    1. 1
    while(new char != NULL) {}

    Запостил: JavaScript, 22 Февраля 2017

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

    • CharNext вроде, не?
      Ответить
      • Охбля... Не рассмотрел сослепу, что это UB. Минусуйте.
        Ответить
        • Где тут UB, СТЁРТОР?
          Ответить
          • Invalid address: [email protected]_You must provide at least one recipient email address. :(
            Ответить
          • не стёртор, а доктор Стертор. Я х.з. как работает с памятью C++, но здесь явно утечка.
            В Делфи большинство объектов имеют фабрику (конструкторы там всякие, деструкторы), а здесь объект инициализируется именно вызовом new.

            Вот, что штампуют в википездии:
            new — оператор языка программирования C++, обеспечивающий выделение динамической памяти в куче. За исключением формы, называемой «размещающей формой new», new пытается выделить достаточно памяти в куче для размещения новых данных и, в случае успеха, возвращает адрес выделенного участка памяти. Однако, если new не может выделить память в куче, то он передаст (throw) исключение типа std::bad_alloc. Это устраняет необходимость явной проверки результата выделения. После встречи компилятором ключевого слова new им генерируется вызов конструктора класса[1].
            Ответить
            • Но утечка памяти это не UB
              Ответить
            • Утечка памяти — это нежелательное поведение. Но оно не является ни неопределённым, ни неожиданным. В данном коде мы пытаемся выделить память и в случае удачи... теряем указатель на выделенный блок. Значит, мы целенаправленно создаём «висячие» блоки, к которым у нас не будет доступа и которые не будут убраны.

              > Однако, если new не может выделить память в куче, то он передаст (throw) исключение типа std::bad_alloc.

              А вот это уже ценное замечание. Если в случае неудачи аллокатор бросает исключение и никогда не возвращает NULL, то данный код компилятор может оптимизировать до такого:
              while(true) {new char;}

              Всё равно выход из цикла только по исключению.

              Тем не менее, «неоптимизированная» форма ошибкой не является. Ошибкой является то, что мы никуда не сохраняем полученный указатель.
              Ответить
              • Кто-кто передаст?
                Ответить
              • Аллокация - это побочный эффект? Компилятор не имеет права соптимизировать этот нью нах?
                Ответить
                • Не имеет -- вдруг new в этом месте волшебный и всегда делает throw?
                  Ответить
                  • Дай пруфы. memcpy во внешней либси тоже может быть волшебный, что не мешает компилятору выкидывать его вызовы из кода.
                    Ответить
                    • Сколь угодно волшебный memcpy должен следовать контракту, описанному в стандарте: не кидать исключений, копировать из валидного src в валидный dst. Любые оптимизации в рамках этого контракта допустимы, с условием сохранения наблюдаемого поведения программы.

                      new может быть определён пользователем и следует другому контракту: либо кидает исключение, либо выдаёт новый кусочек памяти. Оптимизации всё равно должны учитывать оба варианта этого поведения.
                      Ответить
                  • Я погуглил за тебя - ты обосрался.
                    http://stackoverflow.com/questions/31873616/is-the-compiler-allowed-to-optimize-out-heap-memory-allocations

                    > This is allowed by N3664. This proposal is part of the C++14 standard, so in C++14 the compiler is allowed to optimize out a new expression (even if it might throw).
                    Ответить
                    • Не обосрался! Не читайте до обеда stackoverflow.

                      An implementation is allowed to omit a call to a replaceable global allocation function (18.6.1.1, 18.6.1.2). When it does so, the storage is instead provided by the implementation or provided by extending the allocation of another new-expression. The implementation may extend the allocation of a new-expression e1 to provide storage for a new-expression e2 if the lifetime of the object allocated by e1 strictly contains the lifetime of the object allocated by e2, e1 and e2 would invoke the same replaceable global allocation function, and, for a throwing allocation function, exceptions in e1 and e2 would be first caught in the same handler.

                      Выкинутый new обязательно должен быть склеен с другим new (то есть хотя бы один new должен остаться), либо результат должен быть "provided by the implementation", а никакая реализация не сможет бесконечно выделять новую память, и в конце концов кинет исключение.
                      Ответить
                      • > provided by the implementation
                        Т.е. в общем-то и на стеке может запилить, если увидит пару из new и delete, а указатель наружу не утекает.
                        Ответить
                        • Если указатель и утекает, то все равно может на стеке запилить - так и так висячий указатель будет (на стек или в кучу). Главное, чтобы лайфтайм объекта был такой же, как до оптимизации.
                          Ответить
                      • "provided by the implementation" говорит о том, что все эти исключения из new компилятору пофиг и он может хоть на стеке память выделить. А если так, то если он видит, что эта память не используется, то может вообще ничего не аллоцировать (как он это делает с обычными автоматическими переменными).

                        Вот шланг выпиливает new из кода выше https://godbolt.org/g/QrWwRk
                        Ответить
                        • Вот говно :(
                          Ответить
                          • в твоих штанах
                            Ответить
                            • А если написать оператор, то он его не выпиливает:
                              https://godbolt.org/g/FveCUw
                              Видимо, тут он пользуется какими-то своими знаниями о дефолтном операторе new, а не о конструкции выделения памяти.
                              Ответить
                        • это, кстати, забавно. По идее, компилятор при оптимизациях может делать всё что угодно, лишь бы не менять наблюдаемое поведение (за исключением copy elision и RVO). Вот только иногда наблюдаемое поведение таки меняется: https://godbolt.org/g/46zi1e
                          Ответить
                          • А так не меняется: https://godbolt.org/g/FveCUw
                            Ответить
                          • Кстати, а утечка памяти относится к UB?
                            Ответить
                            • Если я прав, и в стандарте с++17 ничего не поменяли, то нет. Нежелательное, но тем не менее определенное поведение.
                              Ответить
              • А почему не malloc вместо new он, говорят, быстрее. Так же я бы рекомендовал за один присест выделять больше чем sizeof(char).
                Ответить
                • А тут как в армейском анекдоте про копание ямы ломом: «Мне не нужно, чтобы вам было удобнее. Мне нужно, чтобы вы задолбались».
                  Ответить
              • исключения можно отключить из настроек компилятора.
                Ответить
    • [:llllllllllllllllllll:]
      Ответить
    • JavaScript фальшивый! Настоящий JavaScript аллоцирует память блоками, чтобы побыстрее было. И в реальных движках используют не тормознутое "{}", а оптимизированное ";"
      Ответить

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