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

    Слушай, а где в стандарте про это написано? Просто интересно.
      Цитата Flex Ferrum @
      Слушай, а где в стандарте про это написано? Просто интересно.
      Я образно выразился. Само по себе состояние не может быть UB. А вот использование значения неинициализированной переменной вполне себе может быть UB.
      Сообщение отредактировано: applegame -
        Цитата applegame @
        Я образно выразился. Само по себе состояние не может быть UB. А вот использование значения неинициализированной переменной вполне себе UB.

        И опять: в стандарте это какой пункт?
          Цитата Flex Ferrum @
          И опять: в стандарте это какой пункт?
          Понятия не имею. Мне не нужно подтверждение стандарта, чтобы понять что это UB:
          ExpandedWrap disabled
            auto s = "abcde";
            size_t a;
            char c = s[a];
          Сообщение отредактировано: applegame -
            Цитата applegame @
            Понятия не имею. Мне не нужно подтверждение стандарта, чтобы понять что это UB:

            Ээээ! Мы о разных вещах говорим. Обращение к переменной литерального типа, которая default-initialized - это само по себе UB или нет?
              Цитата Flex Ferrum @
              И опять: в стандарте это какой пункт?

              ISO/IEC 14882:2014 4.1/2
                Ох. Какие-то бессмысленные хождения по кругу.

                Язык должен быть последовательным. В контексте обсуждаемого вопроса мне бы хотелось, чтобы было единообразное поведение для всех типов.
                Это логично, практично и приводит к меньшему числу ошибок в обобщенном коде. Так же положительно сказывается и на обучении языку новичков.
                Чем меньши исключений из правил, тем проще вникать в язык.
                Это означает, что мы должны определиться в каких случаях мы вызываем конструкторы по умолчанию, а в каких нет. И это решение не должно зависить от типа(или "вида" типа).

                Следователно, у нас 3 варианта(вне зависимости от языка):

                1) Не инициализировать:
                ExpandedWrap disabled
                  my_type a; // невалидное значение, всегда некоторый мусор, всегда требует дальнейшей инициализации
                  ...
                  a = my_type();


                2) Инициализировать неявно
                ExpandedWrap disabled
                  my_type a; // всегда вызов my_type()


                3) Инициализировать явно
                ExpandedWrap disabled
                  my_type a{...};

                Во 2) и 3) случае можно добавить =void(или аналог). Вводить ли его - вопрос отдельный. Как и детали реализации. Думаю, что для этого случая у типов должен быть отдельный конструктор.
                Выбор варианта это наш (1) вопрос в нашем обсуждении. =void - один из подвопросов.

                С++ единственный известный мне язык, который сочетает разное поведение в рассматриваемом случае. Он, как Си, не инициализирует(в некоторых местах, надо заметить) часть типов, но, вводит совершенно другие правила для другой части типов.
                Это нелогично. Это ухудшает ситуацию с обобщенным кодом. Это приводит к багам от неинициализированных переменных. Это отпугивает новичков и негативно сказывается на репутации языка.
                Согласие/несогласие с этими утверждениями - это вопрос (2).

                Изменить ли поведение C++ в данном случае - это (3) вопрос.

                Рассмотрим вопросы
                (1) Выбор варианта. На мой взгляд второй вариант наиболее предпочтителен(напомню, мы тут не только о C++). =void можно добавить. С отдельным конструктором.

                (2) Тут моя позиция ясна :)

                (3) Вводить ли вызов дефолтного конструктора для всех типов в C++. Тут сложнее.

                Достоинства:
                1) единообразие
                2) устранение ошибок неинициализированных переменных(и давайте перестанем их путать с ошибками неверной инициализации - это разные вещи)

                Недостатки:
                1) выполнение дополнительных действий(и потенциальная двойная инициализация)
                2) в редких случаях ошибки с "забытой" верной инициализацией могут быть подавлены(в отличие от текущей ситуации, когда программист получит предупреждение)

                Первый недостаток. Оптимизации компилятора в некоторых случаях могут помочь. Там, где не могут, после профайлинга вставим =void.
                Второй недостаток решается, например, сохранением данного предупреждения для POD типов по отдельному флагу. Не вижу для этого препятствий.
                Сообщение отредактировано: D_KEY -
                  Цитата MyNameIsIgor @
                  ISO/IEC 14882:2014 4.1/2

                  Не до конца догнал ссылку. Процитируешь?

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

                  Язык изначально разделяет встроенные и пользовательские типы. Так уж он устроен. И в своём подходе к каждому из разновидностей типов он последователен.


                  Цитата D_KEY @
                  С++ единственный известный мне язык, который сочетает разное поведение в рассматриваемом случае. Он, как Си, не инициализирует(в некоторых местах, надо заметить) часть типов, но, вводит совершенно другие правила для другой части типов.
                  Это нелогично. Это ухудшает ситуацию с обобщенным кодом. Это приводит к багам от неинициализированных переменных. Это отпугивает новичков и негативно сказывается на репутации языка.
                  Согласие/несогласие с этими утверждениями - это вопрос (2).

                  Не совсем так. Обобщённый код можно из этого перечня исключить. Поменять default initialization на zero initialization в обобщённом коде не просто, а очень просто. Достаточно написать T a = T(); И в этом, собственно, вся соль. В случае явной инициализации поведение встроенных типов не отличается от поведения пользовательских - используется zero initialization. И тут мы возвращаемся к сути дискуссии. Если программист использует в программе default-инициализацию, то, предполагается, что он знает, что делает. А именно: его устраивают все предусматриваемые языком правила для такой инициализации. Понимаешь? Все UB, UB и ID с этим связанные.

                  И опять смешиваются понятия, применяемые для типа, и понятия, применяемые для использующего тип кода. Если их разделить - то всё становится на свои места и противоречий не возникает.
                    Цитата D_KEY @
                    С++ единственный известный мне язык, который сочетает разное поведение в рассматриваемом случае. Он, как Си, не инициализирует(в некоторых местах, надо заметить) часть типов, но, вводит совершенно другие правила для другой части типов.
                    Приходилось мне писать как-то класс, у которого инициализация по умолчанию оставляла мусор в значении (так надо было). И ничего, компилятор вполне справился с поставленной задачей. Можно было этот класс даже в union заталкивать, и он там работал так, как ожидается от какого-нибудь int. Более того, при создании переменной для её конструирования ни одной команды не генерировалось, как и для встроенного int.
                    Так что это вопрос не к языку, а к разработчикам классов, что они не умеют так спроектировать свой класс, чтобы конструирование по умолчанию не вызывало ненужных манипуляций с памятью.
                    Вообще, в C++ разрешение объявлять переменные в произвольном месте внутри блока появилось именно затем, чтобы по возможности избежать неявной инициализации.
                      Цитата Flex Ferrum @
                      Язык изначально разделяет встроенные и пользовательские типы. Так уж он устроен.

                      C++? Да, разделяет. Но это не идет ему на пользу. И да, если мне не изменяет память, то Страуструп при разработке языка хотел этого разделения избежать.

                      Цитата
                      В случае явной инициализации поведение встроенных типов не отличается от поведения пользовательских - используется zero initialization.

                      Ага. Вопрос в том, почему бы ее всегда не использовать?
                      Смотри:
                      ExpandedWrap disabled
                        template<typename T>
                        void foo()
                        {
                        ...
                        T x;
                        ...
                        }

                      Какие у нас требования к T?

                      Цитата
                      Если программист использует в программе default-инициализацию, то, предполагается, что он знает, что делает. А именно: его устраивают все предусматриваемые языком правила для такой инициализации. Понимаешь? Все UB, UB и ID с этим связанные.

                      Если бы еще программисты не делали ошибок... Лучше, когда потенциальная ошибка выглядит в коде явно, чем наоборот.

                      Цитата
                      И опять смешиваются понятия, применяемые для типа, и понятия, применяемые для использующего тип кода.

                      Ничего не смешивается :)
                        Цитата D_KEY @
                        C++? Да, разделяет. Но это не идет ему на пользу. И да, если мне не изменяет память, то Страуструп при разработке языка хотел этого разделения избежать.

                        Сложно сказать. Может и не идёт. А может и идёт.

                        Цитата D_KEY @
                        Какие у нас требования к T?

                        default-constructable. Для встроенных типов это по умолчанию выполняется. Поэтому написать T x = T{}; всегда можно.

                        Цитата D_KEY @
                        Если бы еще программисты не делали ошибок... Лучше, когда потенциальная ошибка выглядит в коде явно, чем наоборот.

                        Угу. Всё верно. И вот именно здесь нужно ещё раз перечитать Крайзера, который как раз и говорит о том, что детерминированное неправильное поведение хуже недетерминированного.

                        Цитата D_KEY @
                        Ничего не смешивается

                        Смешиваются смешиваются. Семантика значения путается с инвариантом типа. А это - разные вещи. :)
                          Цитата Flex Ferrum @
                          Цитата D_KEY @
                          Если бы еще программисты не делали ошибок... Лучше, когда потенциальная ошибка выглядит в коде явно, чем наоборот.

                          Угу. Всё верно. И вот именно здесь нужно ещё раз перечитать Крайзера, который как раз и говорит о том, что детерминированное неправильное поведение хуже недетерминированного.

                          Он говорит довольно спорные вещи, при этом отказываясь от диалога и ответов на вопросы(а так же переходит на личности, но это уже отдельная тема).

                          Цитата
                          Цитата D_KEY @
                          Ничего не смешивается

                          Смешиваются смешиваются. Семантика значения путается с инвариантом типа. А это - разные вещи. :)

                          В каком месте это происходит? Разговор о последовательности языка, единообразии и явном/неявном.
                          Сообщение отредактировано: D_KEY -
                            Цитата
                            4.1 Lvalue-to-rvalue conversion [conv.lval]
                            1 A glvalue (3.10) of a non-function, non-array type T can be converted to a prvalue.55 If T is an incomplete
                            type, a program that necessitates this conversion is ill-formed. If T is a non-class type, the type of the
                            prvalue is the cv-unqualified version of T. Otherwise, the type of the prvalue is T.56
                            2 When an lvalue-to-rvalue conversion occurs in an unevaluated operand or a subexpression thereof (Clause 5)
                            the value contained in the referenced object is not accessed. In all other cases, the result of the conversion
                            is determined according to the following rules:
                            — If T is (possibly cv-qualified) std::nullptr_t, the result is a null pointer constant (4.10).

                            — Otherwise, if T has a class type, the conversion copy-initializes a temporary of type T from the glvalue
                            and the result of the conversion is a prvalue for the temporary.

                            — Otherwise, if the object to which the glvalue refers contains an invalid pointer value (3.7.4.2, 3.7.4.3),
                            the behavior is implementation-defined.

                            — Otherwise, if T is a (possibly cv-qualified) unsigned character type (3.9.1), and the object to which
                            the glvalue refers contains an indeterminate value (5.3.4, 8.5, 12.6.2), and that object does not have
                            automatic storage duration or the glvalue was the operand of a unary & operator or it was bound to a
                            reference, the result is an unspecified value.57

                            — Otherwise, if the object to which the glvalue refers contains an indeterminate value, the behavior is
                            undefined.

                            — Otherwise, the value contained in the object indicated by the glvalue is the prvalue result.
                            3 [ Note: See also 3.10.—end note ]

                            Поэтому
                            ExpandedWrap disabled
                              int x;
                              int y = x; //undefined behavior
                              int z;
                              z = 5; // OK

                            Цитата Flex Ferrum @
                            default-constructable. Для встроенных типов это по умолчанию выполняется. Поэтому написать T x = T{}; всегда можно.

                            Нет, T x = T{} требует move-constructible.
                              Цитата D_KEY @
                              Qraizer, твой высокомерный тон и переход на личности не делает тебе чести.
                              Я знаю. Он как-то говорил, что ему фиолетовы тупые оппоненты, и он не имеет желания ни общаться с ними, ни объяснять то, что можно прочитать в умных книжках или нагуглить. Я долго был в нему лоялен. Даже в тематике, за что тем не менее в отместку получал то же неблагодарное "фиолетовое" отношение. Сколько, ты помнишь? Год? Два? Четыре? Так вот, с лета мне тоже фиолетово его мнение и кривляние, и по отношению к нему я принял ровно такую же позицию. Он далеко не дурак, как прикидывается.
                              Цитата D_KEY @
                              Цитата Qraizer @
                              От банки его спасает тот факт, что он неспособен понять терминов "инвариант" и "состояние объекта", а также неприменимость этих терминов к POD

                              А что если что-то не понимаешь ты, а? Подумай об этом.
                              Конкретно на последней паре страниц я не понимаю смысла его нарочитого дебилизма. Если объяснишь, буду признателен. В остальном непонимания чего-ибо у меня нет, или я этого не вижу. Покажи, если видишь ты.
                              Цитата D_KEY @
                              А банить-то за что?
                              Банка != бан. Если бы я не начал свой встречный наезд, пришлось бы выписать из-за нарушения пункта 3 Правил раздела, т.к. его аргументы противоречат тем самым терминам, о смысле которых он на самом деле прекрасно знает, и значит аргументами не являются, а также пункту 4, т.к., в связи с 3, две страницы его перлов суть сплошь маразм. А теперь выписать будет уже несправедливо, поэтому нельзя. Но можно справедливо поотклонять посты. Пусть Flex Ferrum займётся, если хочет. Я не буду, потому что фиолетово.

                              Добавлено
                              Цитата applegame @
                              А что ты назывешь POD? Классы и структуры тоже могуть быть POD. Да и с какого перепугу я не могу применить термин "инвариант" и "состояние объекта" к какому-нибудь int? У неинициализированного int состояние вполне известно - UB. Шире надо мыслить, мир одним только C++ не ограничивается.
                              Разделение встроенных типов от невстроенных - это всего лишь твоя прихоть. В C++ введено множество стредств для того, чтобы эту разницу нивелировать насколько это возможно.
                              Что такое POD, определяется Стандартом. Если у тебя int несёт некую смысловую нагрузку, это ещё не делает его не-POD. Если он у тебя получил состояние и инвариант, это тоже не делает его не-POD. Это твоя прихоть считать его не-POD.
                              Моя прихоть лишь в том, что структурами я называю POD, а классами не-POD. Но и это не столько моя прихоть, сколько устоявшиеся укороченные выражения.

                              Добавлено
                              Цитата D_KEY @
                              1) Не инициализировать
                              ...
                              2) Инициализировать неявно
                              ...
                              3) Инициализировать явно
                              1. Отклоняется. Для не-POD отсутствие инициализации критично из-за полагающихся на инварианты методов. Уберём – получим Дельфийный бардак. И это в лучшем случае.
                              2. Выгода сомнительна. Недёшева в реализации с риском получить непропорционально затраченным усилиям малый профит.
                              3. Запрет на неинициализированность POD лично мне кажется лучшим выбором. В своей практике я использовал определения POD без инициализации только в двух случаях:
                                • когда было нужно выполнить инициализацию функцией, принимающую ссылочный (возможно, по указателю) неконстантный параметр;
                                • когда часто чередующиеся строки с исполнительными выражениями и выражениями определений выглядели некрасиво, и определения на фоне исполнительных конструкций плохо видны.
                                Первые дадут критически малый оверхед в подавляющем большинстве случаев, т.к. работа функции наверняка будет куда более затратна, а в остальных = void руки не отвалятся. Вторые можно пережить, хотя читающему код и будет хотеться материться.
                              Боюсь только, что придётся сильно обдуматься вопросом касательно POD-структур. Лично я, кроме конструктора, лёгких путей решения не вижу.

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

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

                                Первые дадут критически малый оверхед в подавляющем большинстве случаев, т.к. работа функции наверняка будет куда более затратна, а в остальных = void руки не отвалятся. Вторые можно пережить, хотя читающему код и будет хотеться материться.
                                С этим похоже все здесь присутствующие согласны. Я тоже, подумав, согласился.
                                Цитата Qraizer @
                                Посчитай, сколько раз я в этой теме упомянул тесты, например, как более практичный, надёжный и дешёвый способ поиска пропущенных компилятором неинициализированностей. И что, это возымело эффект? И после этого я, оказывается, не иду на диалог. :whistle: Ну да, ну да.
                                Твоя аргументация сводится к
                                Цитата Qraizer @
                                Ну если васрать, то static_cast<> вам в помощь.
                                и
                                Цитата Qraizer @
                                Но тестеры на тёмной стороне, и просто обожают UB, не знал?


                                Что такое "васрать"?
                                Сообщение отредактировано: applegame -
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (42) « Первая ... 38 39 [40] 41 42 


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0957 ]   [ 15 queries used ]   [ Generated: 27.04.24, 19:39 GMT ]