На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела:
1. Название темы - краткое описание кто/что против кого/чего
2. В первом сообщении - список параметров, по которым идет сравнение.
3. Старайтесь аргументировать свои высказывания. Фразы типа "Венда/Слюникс - ацтой" считаются флудом.
4. Давайте жить дружно и не доводить обсуждение до маразма и личных оскорблений.
Модераторы: Модераторы, Комодераторы
Страницы: (42) « Первая ... 32 33 [34] 35 36 ...  41 42  ( Перейти к последнему сообщению )  
> Инициализировать или не инициализировать , it's the question
    Цитата applegame @
    И в чем тут ошибка?
    Вот ответ:
    Цитата JoeUser @
    Если выделение однократное, проверять нужно не сперва, а потом, со значением MAP_FAILED.
    В данном коде начальная инициализация в 0 некорректна. mmap() при успехе может вернуть 0.
    Сообщение отредактировано: Qraizer -
      Qraizer, я не понял к чему твой пример. Даже если твой мегатест сможет найти неинициализированную переменную, то от ошибки в приведенном коде это не избавит :-?

      Добавлено
      Цитата Qraizer @
      В данном коде начальная инициализация в 0 некорректна

      Так. И? Дело ведь не в том, корректен ли 0 для какого-то типа в той или иной задаче(это дело абстракций другого уровня), а в том, что проинициализированное значение лучше мусора.

      Добавлено
      Вот скажем, с чего ты взял, что, например, пустая строка является корректным значением в каком-то конкретном случае? Нет у нас оснований так утверждать. Но
      ExpandedWrap disabled
        std::string str;

      Создаст пустую строку, а не какой-то мусор в памяти.
        Цитата JoeUser @
        Выделение памяти будет только в случае предварительной инициализации shMem нулем (NULL). Если предварительной инициализации не было (мусор), то выделение будет случайным образом.
        Дык речь как раз и шла об инициализации нулем.
        Цитата JoeUser @
        А код дурацкий. Имхо, имеет смысл так делать только в случае перевыделения по непонятным заранее зависимостям. Если выделение однократное, проверять нужно не сперва, а потом, со значением MAP_FAILED.
        Именно так, но по приведенной Qraizer'ом строке ничего понять невозможно. Я почитал доки: mmap может вернуть (void*)-1, что и есть MAP_FAILED. Я решил, что это не ошибка. Может там в следующей строке проверка идет.
        Цитата Qraizer @
        В данном коде начальная инициализация в 0 некорректна. mmap() при успехе может вернуть 0.
        Интересно в каком случае mmap может вернуть 0? И чем лучше будет здесь проинициализированная мусором переменная?
        Сообщение отредактировано: applegame -
          Цитата MyNameIsIgor @
          Используйте =void и не будет у вас оверхеда.

          Ещё раз. Это:
          1. Заставляет переписать весь legacy-код
          2. Неявным образом меняет семантику legacy-кода
          3. Ставит ряд интересных вопросов, связанных с тем, как в таком случае инициализировать члены-POD-структуры, массивы POD-структур и т. п.
          4. Забавным образом меняет грамматику языка - void теперь может встречаться не только в левой части декларации, но и в правой, в качестве инициализатора.
            Цитата Flex Ferrum @
            1. Заставляет переписать весь legacy-код
            2. Неявным образом меняет семантику legacy-кода
            3. Ставит ряд интересных вопросов, связанных с тем, как в таком случае инициализировать члены-POD-структуры, массивы POD-структур и т. п.
            4. Забавным образом меняет грамматику языка - void теперь может встречаться не только в левой части декларации, но и в правой, в качестве инициализатора.

            1. Менять вполне можно постепенно.
            2. Хм. Разве верно работающий код поменяет свою семантику хоть каким-то существенным образом?
            3. Например?
            4. Не вижу особых проблем с этим. Кстати, можно и отдельное слово завести.
              Цитата Flex Ferrum @
              1. Заставляет переписать весь legacy-код

              Нет, не заставляет. Если только код не полагается на особенный мусор в неициализированных переменных :jokingly:
              Цитата Flex Ferrum @
              2. Неявным образом меняет семантику legacy-кода

              Как я уже говорил - она изменится только во временных параметрах. Уверен, что мест, где будет необходимо проставить = void ради оптимизации окажется исчезающе мало.
              Цитата Flex Ferrum @
              3. Ставит ряд интересных вопросов, связанных с тем, как в таком случае инициализировать члены-POD-структуры, массивы POD-структур и т. п.

              Так же, как и примитивных типов - инициализировать и всё.
              Цитата Flex Ferrum @
              4. Забавным образом меняет грамматику языка - void теперь может встречаться не только в левой части декларации, но и в правой, в качестве инициализатора.

              Здесь с рождения контекстно-зависимая грамматика, где даже ключевые слова не всегда ключевые слова. А это изменение вообще микроскопическое.
                Цитата Qraizer @
                Допустим, программер написал
                ExpandedWrap disabled
                  if (shMem == 0) shMem = mmap(0, SHM_SIZE, PROT_WRITE | PROT_READ, MAP_SHARED, GetFileNameFromUser(), 0);
                Как быстро ты найдёшь тут ошибку, и ориентировочно сколько времени она может жить в продакшне?

                Если переменная была неинициализирована, то сказать что-то определенное будет сложно. Но через какое-то время мы, вероятно, таки словим баг и найдем причину - неинициализированная переменная. Поскольку кто-то написал == 0, то, вероятно, проинициализируют ее так же 0... Так как это относится к теме?
                  Цитата D_KEY @
                  Qraizer, я не понял к чему твой пример. Даже если твой мегатест сможет найти неинициализированную переменную, то от ошибки в приведенном коде это не избавит :-?
                  :facepalm: Не сможет. Неважно, как изначально будет инициализирована нулём shMem, явно или неявно. D_KEY, я устал повторять, что тесты в принципе неспособны зафейлить алгоритм, если он неверно задокументирован. Только — если реализация отличается от заявленного в документации...
                  Цитата D_KEY @
                  Дело ведь не в том, корректен ли 0 для какого-то типа в той или иной задаче(это дело абстракций другого уровня), а в том, что проинициализированное значение лучше мусора.
                  ...зато тесты влёгкую находят огромный % UB из-за неопределённых входных значений.

                  Добавлено
                  Цитата applegame @
                  Именно так, но по приведенной Qraizer'ом строке ничего понять невозможно. Я почитал доки: mmap может вернуть (void*)-1, что и есть MAP_FAILED. Я решил, что это не ошибка. Может там в следующей строке проверка идет.
                  Ошибка в условии shMem == 0. Правильно будет shMem == MAP_FAILED. Соответственно инициализирующим значением тоже должно быть MAP_FAILED, а не 0 или не дай боже nullptr.
                  Сообщение отредактировано: Qraizer -
                    Цитата Qraizer @
                    В данном коде начальная инициализация в 0 некорректна. mmap() при успехе может вернуть 0.

                    А, по-моему, вполне корректна. Но абсолютно бессмысленна. По сути - двойная инициализация, сперва нулем, а потом результатом функции. И кому это нужно, если все равно проверять результат работы функции по-любому надо. Вывод - инициализация нулем есть бессмысленное действие, не приносящее профита.
                      И ещё повторю, потому что потерялось в гуще страниц назад. Я не ратую за то, чтобы ловить отсутствие требуемой инициализации тестами. Существует большое количество других способов найти такие места, от диагностики компилятора до отладочных билдов, напичканных теми или иными формами assert()-ов. Однако когда речь идёт о серьёзных продуктах, то наличие тестов для них суть обычное явление, и я просто не вижу необходимости перекладывать задачу, которая и так мимоходом решается тестами, на плечи Комитета.
                        Цитата Qraizer @
                        Неважно, как изначально будет инициализирована нулём shMem, явно или неявно.

                        И зачем тогда этот код тут?

                        Цитата
                        D_KEY, я устал повторять, что тесты в принципе неспособны...

                        Я не понимаю, зачем ты вообще о тестах заговорил.

                        Цитата
                        Ошибка к условии shMem == 0. Правильно будет shMem == MAP_FAILED. Соответственно инициализирующим значением тоже должно быть MAP_FAILED, а не 0 или не дай боже nullptr.

                        И какой вывод-то?
                          JoeUser, это зависит от архитектуры приложения. Например, shMem может быть просто общей межпроцессной памятью без привязки к файлу. Тогда if() проверяет, подключились ли мы к этому региону или ещё нет, а момент, когда это становится возможным, вполне может определяться не то что в run-time, а вообще действиями пользователя, перед которым окошко "Контроллер репликаций не запущен. Перед повторной попыткой устраните проблему" с кнопочками, "повторить попытку соединения" в частности.

                          Добавлено
                          Цитата D_KEY @
                          Я не понимаю, зачем ты вообще о тестах заговорил.
                          Перечитай ещё раз. Продолжай, пока понимание не появится. Что тут ещё можно посоветовать. Если ты считаешь, что чётко определённое неправильное поведение лучше, чем неопределённое, но обнаруживаемое на первой же ночной сборке, то нам не о чем разговаривать.
                            Цитата Qraizer @
                            Что тут ещё можно посоветовать. Если ты считаешь, что чётко определённое неправильное поведение лучше, чем неопределённое, но обнаруживаемое на первой же ночной сборке, то нам не о чем разговаривать.

                            Я просто не понимаю, с чего ты взял, что после обнаружения там не поставят инициализацию 0. По-моему, если написали == 0, то, скорее всего, таким "фикс" и будет.
                              Цитата Qraizer @
                              JoeUser, это зависит от архитектуры приложения.

                              Ну так я и написал почти тоже самое ранее:

                              Цитата JoeUser @
                              Имхо, имеет смысл так делать только в случае перевыделения по непонятным заранее зависимостям.

                              И тогда уж инициализировать заранее MAP_FAILED. Тогда в очередной итерации попытки выделения определим, что память таки выделилась.
                                Хорошо, D_KEY, поясню подробно, но больше не буду.
                                Trivia 1. Этот холивар начинался с несколько другой темы. А именно: нужно ли всегда, даже избыточно, инициализировать POD. Но потом она вылилась в ту дискуссию, которая и сейчас продолжилась: пусть это делает компилятор или же всё-таки программист. Который раз обращаю внимание, что это два разных вопроса. И второй рассматривается только в том случае, если ответ на первый "да, всегда, даже если избыточно. К такому ответу приводит аргумент, что, мол, нет разницы, будет ли дефолтным поведение без инициализации, и для его отмены эту инициализацию надо указать явно, или наоборот, дефолтным будет zero-initialize, а для его отмены надо явно её отменить = void. Так вот, я не согласен как раз с этим отсутствием разницы.
                                Trivia 2. Заранее хочу обратить внимание ещё на один факт. В любом решении этих вопросов всё равно будет присутствовать человеческий фактор. Его не избежать. Никак. Ситуация прямо такая же, как если бы рассматривался вопрос о поведении программиста, получившего какой-нибудь conversion from "int" to "short" may lose significant bits. Все мы прекрасно понимаем, что банальный static_cast<>, затыкающий рот компилятору, не всегда является правильным решением. Хотя и часто. Так что дело компилятора – ткнуть носом, а дальше человек должен думать сам. Вопрос только, насколько велика вероятность принять тому неверное решение. Если её можно понизить, её нужно понизить. Наличие диагностики компилятора в рассматриваемом случае эту вероятность снижает, хотя и не устраняет полностью. Но устранить её полностью невозможно, а если завтра вдруг окажется возможным, то послезавтра программисты с почётом отправятся на биржу труда учиться махать лопатами.
                                К делу. Человек по сути лентяй. Есть исключения в лице трудоголиков, но увы, большинство из нас лентяи, и мы не хотим делать что бы там ни было, если этого можем избежать. Поэтому "int x;" и баста. Так короче. Ой, uninitialized var is used. "А, ну да, тут же надо = 0; ...или не 0 :scratch: ?" Что, задумался? Правильно сделал, потому что 0 не всегда правильно. Хотя и часто. А что если "int x = void;"? Та ничего. Никто это = void писать не будет из лени. Человек должен думать, а работать вместо него должна машина. Если вдруг понадобится поработать человеку, его надо заставить, а вероятнее всего это осуществит мотивация думать. Медитация над диагностикой например. А вот вбивание = void – это всё-таки работа. Неприятная. Поэтому не будет он этого писать. Поэтому он никогда не будет получать диагностики об отсутствующей инициализации. И это хотя и часто будет работать, но не всегда. И "не будет получать диагностики", Карл! Это значит, что с неявным zero-initialize из-за отсутствия диагностики вероятность не заметить ошибку неправильной инициализации выше, чем в нынешнем виде Стандарта не заметить ошибку отсутствия (не избыточной) инициализации. Как вариант, из той же лени народ придумает себе скрипт, расставляющий эти самые = void, чтобы вернуть диагностику. Ну и зачем тогда это всё?
                                Так что вот, я не согласен с отсутствием разницы. И неважно, насколько на самом деле часто допускаются те и те. Пусть и одна ошибка неверной инициализации на 1000 отсутствующей. Эта одна задокументирована, и поэтому имеет ровно нулевую вероятность быть обнаруженной формальными методами. А та тысяча имеет ненулевую вероятность проявиться даже в банальных автотестах, не то что писаных руками средненького верификатора, только-только прошедшего испытательный.

                                Добавлено
                                Резюмирую. С изменением правила неявной инициализации POD на zero-initialized мы сокращаем количество отсутствующей инициализации до нуля и полностью избавляемся от связанных с этим ошибок. Но: во-первых, взамен мы получаем некие, во многих случаях исчезающе малые, оверхед и избыточность, но в ряде случаев они окажутся не так уж малыми, а значит надо предоставить способ подавлять zero-initialized, ежели вдруг, и на этом всё, нулевая вероятность тут же становится немного положительной, т.е. полностью проблема не решена; во-вторых, взамен мы получаем принципиально хуже обнаруживаемые ошибки неверной инициализации, тогда как для обнаружения отсутствующей инициализации уже разработаны развитые формальные средства и методы, хорошо автоматизируемые, т.е. надёжность итогового кода в продакшн не становится однозначно выше; в-третьих, если програмист C++ — напомню, изначально холивар был выделен из тематического вопроса про C, но сейчас рассматривается в контексте именно C++ — не пожелал сделать инициализацию прямо в определении, которое в C++ можно ткнуть в любое место блока, а значит определить переменную ровно в том месте, где её уже есть чем инициализировать, и не раньше, то наверное на это есть причины, потому что Плюсник в отличие от Сишника привык мыслить объектами, а не переменными, а у тех есть состояние, и первая мысль у Плюсника, закончившего вбивать имя переменной, должна быть "какое начальное состояние я должен ей дать?", и ежели вдруг его ещё нет, то рассмотреть возможность перенести определение ниже, но т.к. он такой возможности не нашёл, иначе бы не опускал инициализацию, значит отсутствие начального значения – факт, который уже рассмотрен, взвешен, и по нему принято решение ещё до того, как рука потянулась к =, не говоря уже о v, o и остальных двух буквах, не считая опциональных whitespaces; и в-четвёртых, как верно заметил Flex Ferrum, эти изменения не понравятся олимпиллиарду легаси-проектам, 100500 поставляемым реализациям и одному-единственному, но очень занятому Комитету, у которого есть куда более насущные нерешённые вопросы по C++17.

                                Очень краткий итог: ну и на кой хрен это всё затевать в таком случае.
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (42) « Первая ... 32 33 [34] 35 36 ...  41 42


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0721 ]   [ 15 queries used ]   [ Generated: 28.04.24, 04:45 GMT ]