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

      С этим я согласен. Но я не согласен с тем, что для POD на это можно забить. Я уже пояснял, но попробую еще.
      Инварианты инвариантами, но они тут не очень причем. Объект может находиться в одном из корректных состояний(соблюдать инварианты), но неизвестно в каком. Это для нас очень часто неприемлемо, особенно при начале работы с ним(например, при попытке соблюсти уже свои инварианты). Так что дело в предсказуемости состояния при использовании объекта(в широком смысле, int сюда относится).
      ExpandedWrap disabled
        string s; // не мусор, а корректное дефолтное значение
        // ...
        // тут мы работаем с инициализированной строкой
        // даже если она пустая
        // даже если пустое значение нам не подходит и это ошибка
        // ее скорее всего отловят юниты, тесты и т.п.
        // ...

      ExpandedWrap disabled
        int x; // мусор
        // ...
        // тут мы работаем с неиницализированным int
        // получаем, как правило, НЕИЗВЕСТНО что
        // причем оно может работать годами верно,
        // а потом упасть в самый неподходящий момент.
        // ...

      Не все же, как ты, исследуют в тестах память объектов :) У нас, например, таких тестов нет. И я, честно говоря, не вижу смысла тратить на них время.

      Добавлено
      Цитата Qraizer @
      Цитата D_KEY @

      ...
      2) Инициализировать неявно
      ...

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

      Выгода в предсказуемом поведении. В меньшем числе глупых ошибок. Если я написал случайно int x; а нужен был мне 0, то я получу ошибку, причем проявится она неизвестно когда. Если же язык проинициализировал 0 сам, а мне был нужен не 0, а что-то другое, то я довольно быстро эту ошибку обнаружу. Понимаешь о чем я?
      В чем дороговизна реализации?

      Добавлено
      Цитата Qraizer @
      Запрет на неинициализированность POD лично мне кажется лучшим выбором.

      Тут как раз непонятно что делать с кучей старого кода.

      Добавлено
      Qraizer, если хочешь знать мое мнение, ты последнее время чересчур эм... высокомерен, причем это твое качество, ИМХО, росло год от года. Мне кажется, что именно это тебе мешает качественно, емко и точно излагать и аргументировать свою позицию, причем так, чтобы она была понятна твоим оппонентам. А ведь раньше ты этим отличался. Если тебе задают встречные вопросы, то это означает, что люди не поняли(или не приняли) твой аргумент и от тебя требуются что-то уточнить или переформулировать. И очень редко это троллинг. Ты же или отказываешься отвечать или повторяешь то, что уже говорил(кстати, это мне тоже свойственно, но я стараюсь такие вещи замечать и исправлять).

      Добавлено
      Цитата Flex Ferrum @
      Эммм... Ну смотри. Компилятор выдаёт массу диагностики на подозрительные действия программиста. Ну, там, не всегда корректные приведения, вызовы и т. п. В том числе на использование неициализированных переменных. Есть такой варнинг, да.

      Его может не быть. Он может быть разного качества у разных компиляторов. В некоторых случаях выдать такую диагностику сложно или вообще нельзя.
      Мы ведь говорим о языке, а не о компиляторах, да?

      Цитата
      Программист приходит в нужное место кода и думает - а как правильно.

      А если нам компилятор не смог выдать диагностику, то не приходит. А программа, тем временем, ведет себя непредсказуемо.
      Отловить неподходящую инициализацию нулем легче, чем отловить "инициализацию" мусором.

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

      Как я писал выше, никто не мешает сделать для этого предупреждения отдельный флаг. Пусть будет все так же обращать внимание программиста на пропущенную инициализацию POD-типов. Как этому мешает инициализация 0?
      Сообщение отредактировано: D_KEY -
        Цитата applegame @
        Я не понимаю твоей цитаты про человеческий фактор. Точнее саму цитату понимаю, но не понимаю, как она должна помогать твоей аргументации. Поэтому я ее принял к сведению и все. Может вместо того, чтобы лезть в бутылку просто попробовать изъясняться яснее, без туманных намеков?
        Попробую учесть на будущее. Но не обещаю, т.к. мне в свою очередь не понятно, как может быть непонятно, что такое человеческий фактор, и почему его надо минимизировать, а в идеале устранять. Суть поста в том, чтобы показать, что предлагаемые Александреску изменения идеала не достигают, минимизация человеческого фактора получается сомнительной, а последствия воплощения предложения недёшева. Всякоразные "если мне захочется считать int не-POD", "если я наплюю на инварианты std::string", "если кто-то намеренно не проинитит и заюзает как индекс массива" итп имеют отношение в равной степени к любому варианту, хоть нынешнему, хоть предлагаемому, и поэтому сами по себе не играют никакой роли. Зато играет роль вероятность случайно допущенной ошибки в том или ином случае и сложность её обнаружения и нейтрализации. И тривии предназначались для того, чтобы подчеркнуть именно этот аспект рассуждений, а отнюдь не фантазии на тему граничных случаев. И тем не менее балаган всё равно умудрились развести.
        Цитата applegame @
        Касаемо твоей цитаты. Надо ли из нее сделать вывод, что полезность/вредность инициализации по умолчанию или ее отсутствия в конечном итоге решается человеческим фактором? Ну типа, одному человеку оно поможет, а другому помешает.
        Что, ещё раз написать, что ли? Большая часть отсутствующих требующихся инициализаций ловится диагностикой компилятора. Да, это не стандартизировано, потому что нельзя писать в Стандарт того, выполнение чего нельзя обеспечить полностью. Но компилятор, который не отлавливает такие ошибки, которые отлавливают другие, просто не продержится на рынке, его выкинут на помойку. Остальная, весьма небольшая, часть ловится другими средствами. Это уже давно поставлено на поток, и эти технологии прекрасно и надёжно работают. В результате, когда проект доходит до стадий ночных сборок под контролем тестов, таких ошибок скорее всего уже не остаётся. А ежели что, так на то тесты и пишут, вообще-то, чтобы искать неправильное поведение кода. Не, серьёзно, если тест неспособен найти UB из-за неинициализированных данных, отправляйте его автора на переаттестацию. Если неинициализированных данных нет, то нет и UB из-за них, поэтому тестами найти такие ошибки в общем случае нельзя, тут требуется верификация алгоритма, и это задача точно на порядки сложнее.
        Ошибиться и написать неверное инициализирующее значение можно при любом раскладе. Но как говорилось в первой тривии, это два разных аспекта. Речь же там шла об отсутствии инициализирующего значении в определении. Потому что если его там не указано, то его в натуре нет. Ну вот незачем программеру инициализировать переменную, и всё тут, т.е. как говорилось во второй тривии, совсем не из-за забывчивости или злого умысла. Совсем другое дело, что человеческий фактор мог сыграть с ним злую шутку, и он ошибся в оценке того, когда она всё-таки должна уже стать проинициализированной. Такую ошибку допустить куда легче. Если заставить компилятор всегда занулять POD-ы, это никак не поспособствует обнаружению таких ошибок, и даже тесты с большой долей вероятности тут не помогут. Зато набежит толпа индусов.
        Решение о запрете определять POD без инициализации, вообще говоря, самое нормальное, если уж действительно вдруг восхотелось что-то в языке поменять. Но и тут индусы, согласные вместо тебя за полтора цента за штуку вписывать = void куда не попадя, пока ты обедаешь, уже потирают руки в предвкушении. И в конце концов, никто не запрещает уже сегодня прописать в статическом анализаторе соответствующее правило.
        В любом случае мой вывод таков, что при нынешнем положении дел проблема не настолько большая, чтобы решать её ценой потери обратной совместимости с огромным количеством проектов.

        Добавлено
        D_KEY, но ведь я никого тут не трогал до поры до времени, не заметил разве? И в соседней теме всё в порядке. Странно? Вообще-то мнение интересное, но если бы ты следил внимательнее, то заметил бы, что я себе позволяю что-либо только в ответ. Год от года мне всё больше и больше надоедало читать десятки страниц чуши, нагенеренных чьим-либо бездельем и скукой, в которой хорошо если пара постов толковых. Вот летом и надоело в конце-концов. А если это ещё и эпичный бред... Может быть и не стоило на MyNameIsIgor-я наезжать, зато флуд прекратился. Я сам за собой заметил, что мне абсолютно не нравится писать многократно одно и то же. Секундочку, так может быть просто не надо спрашивать одно и то же, а? Ведь это на самом деле просто. Прочитать внимательно, не согласен если, так на здоровье, приводи свои аргументы. Только чтоб это были аргументы, а не чушь несусветная на тему "плохая машина, потому что не поедет, если ей нассать в бензобак". Если что-то непонятно, уточнить, конкретное место указать или термин. Ведь человеческий фактор же, мог и написать с ошибкой, а ведь ещё бывают ошибки в рассуждениях. Так что уточнить непонятное вполне себе полезное действие. Но ведь не переспросить же уже спрошенное на прошлой странице-то! Пишешь, стараешься, аргументы выстраиваешь, связи причин со следствиями аккуратненько подчёркиваешь, а на следующей странице полное впечатление, что пост ушёл в шредер. Очень вежливо? Так чего тогда удивляться встречной реакции? Несколько лет назад... ты помнишь холивары нескольколетней давности? Я вот помню, нормальные были.
          Немного поофтоплю. Одно время мы тестили некую ОС реального времени. Просто один пример. Не самый в чём-то показательный, но любопытный. Некая функция могла при определённых условиях выдать kernel panic и впасть в бесконечный цикл. Как такую тестить? Примерно так:
          ExpandedWrap disabled
            void test_case_01()
            {
              int ret;
             
              /* тут установка входов */
              longjmp_call_count = 0;
              /* ... */
             
              if (setjmp(exitTo) == 0) ret = FunctionUnderTest(/* тут подготовленные параметры */);
             
              /* проверка выходов */
              check_value(longjmp_call_count, cEQ, 0, "kernel panic isn't occured");
              check_value(ret, cEQ, ERR_NO, "FUT returns ERR_NO");
              /* ... */
            }
          Итп. Остальные функции подобны, только значения входов меняются, и ожидаемые значения выходов по-разному. Функция, вызываемая для впадания в панику, застаблена, чтобы предотвратить бесконечный цикл и заодно легко проверить факт её вызова. longjmp_call_count – это глобальная переменная, инкрементится стабом. Сама функция паники имеет атрибут noreturn, что объяснимо, но для целей теста сие не подходит, т.к. он должен продолжать работать, поэтому выход из стаба только нелокальным переходом.
          Чудо gcc пилит тут диагностику о том, что ret, возможно, не будет проинициализирована. И правильное делает, вообще-то, т.к. если longjmp() из стаба сработает, то так и будет. Он не должен сработать, т.к. этот кейз выставляет входы в комбинацию, при которой паники быть не должно, но ведь мы тест или не тест? Кто же верит документации на слово. Поэтому всё равно окаймляем в setjmp(), хоть и проверяем, что оно не сработало. Однако диагностику надо устранить. Так велит "Инструкция по разработке".
          Самое очевидное - заключить проверку ret под if(longjmp_call_count != 0). Но нельзя. В Инструкции чёрным по белому написано, что количество выводимых в отчёт проверок – а check_value() конечно же отчитывается в лог о pass/fail, ожидаемых и полученных циферках и контролируемого отношения между ними, в данном случае cEQ, т.е. равно – должно быть одинаковым независимо от их статуса. Это очень важно, т.к. ночные рераны каждый чек сравнивают с полученным на бэйз-лайновом прогоне, а у чекера снесёт крышу, если количества чеков будут неконтролируемо меняться, тестов как-никак свыше 3500. Так что в неком кейзе пара pass может зафэйлиться или наоборот, но вот общее количество pass+fail должно быть постоянным.
          Самое простое – проинитить ret в определении. Можно, но чем? Во-первых, в отчёте одновременно и "kernel panic isn't occured: :1: <EQ> :0: *** FAILED ***", и "FUT returns ERR_NO :0: <EQ> :0: *** PASSED ***" или наоборот в противоположной ситуации будет смотреться странно. Нужно некое оригинальное значение. Тогда какое? Отличное от ожидаемого, конечно. Во-вторых, беда в том, что меняя ret, я меняю набор входов для кейза, а значит не могу собрать из кейзов пары, явно проверяющих влияния входов, а то и потоки данных. Такой тест многовероятно будет завёрнут ещё на ревью, а не будет, то запросто при валидации, что в 100500 раз хуже. Чтобы этого не было, ret нужно инитить в одинаковые значения во всех кейзах. Но ожидаемое от кейза к кейзу значение возврата меняется, и некоего оригинального и уникального может просто не оказаться. В-третьих, это требует знать значений кодов возврата, т.к. среди разных идентификаторов могут оказаться с одинаковыми значениями. Тем не менее, можно выбрать этот вариант, т.к. не все аудиторы такие злые, что переменные теста считают за входы.
          Но самый правильный вариант:
          ExpandedWrap disabled
              if (setjmp(exitTo) == 0) ret = FunctionAnderTest(/* тут подготовленные параметры */);
                ret = ~ERR_NO;
          Решение подходит лучше всего потому, что ret при любом раскладе перестаёт быть входом, т.к. меняется после возврата из FUT (или стаба). Только надо не забывать менять значение под else, что вообще говоря легко автоматизировать.

          К чему это я. Случай специфический, конечно. Инструкция там, отраслевые стандарты, аудиторы злые. Тем не менее, внезапно, демонстрируется ситуация, когда инициализировать при объявлении нельзя, только после.
            Цитата Flex Ferrum @
            Если когда-нибудь применял паттерн двойной инициализации

            Можно более точное название (или ссылку на описание)? Не могу нагуглить.
              korvin, можешь начать отсюда: http://www.gamedev.net/topic/628002-one-st...itialization-c/
              0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
              0 пользователей:
              Страницы: (42) « Первая ... 40 41 [42] 


              Рейтинг@Mail.ru
              [ Script execution time: 0,0801 ]   [ 15 queries used ]   [ Generated: 29.03.24, 02:08 GMT ]