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

    0

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    class UnitedFigure : public Figure {
        Figure &f1;
        Figure &f2;
    
    public:
        UnitedFigure (Figure &_f1, Figure &_f2) : f1(_f1), f2(_f2) {}
    
        double distance_to(const Point &p) const override {
            return std::min(f1.distance_to(p), f2.distance_to(p));
        }
    }

    Завезли ссылочные поля класса, это в каком стандарте?
    Даже тестил когда то такое, наверное на C++03 и получал ошибку компилятора.
    Я и не знал, что добавили такую прекрасную возможность выстрелить себе в ногу.

    Запостил: YpaHeLI_, 16 Сентября 2020

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

    • Дык с самых первых версий крестов и ввели, базовые же вещи.

      > прекрасную возможность выстрелить себе в ногу
      Чем ссылочные поля отличаются от полей-указателей?
      Ответить
      • В них нуллов не бывает. Одной головной болью меньше.
        Ответить
        • Ну да, с точки зрения безопасности ссылки определённо лучше уко-ко-козателей. Поэтому я и не понимаю претензий ТС.
          Ответить
          • Ну видимо хочет как в расте, чтобы по рукам линейкой били когда Figure выходит из скопа, а UnitedFigure ещё нет.
            Ответить
            • А, ну да, это ж кресты, тут думать надо.[/color]
              Ответить
              • Да, это не шахматы. В футболе вот тоже нужно работать головой.
                Ответить
            • кстати в крестах есть интересная штука для временных объектов, на которые получены константные ссылки - даже если они выйдут из скопа, то доживут, пока живёт константная ссылка на них
              Ответить
              • Но в случаях типа UnitedFigure(Figure(...), Figure(...)) она не спасёт. Все фигуры из аргументов прекрасно сдохнут даже если внешнюю попытаться удержать ссылкой.
                Ответить
              • ты вот про такое
                int foo()
                {
                	return 42;
                }
                
                int main()
                {
                	const int& bar = foo();
                	std::cout << bar;
                	return 0;
                }

                ?

                Внутри main создает временный объект с 42, и должен бы по идее разрушиться сразу, но остается жить?

                Кажется, до 11 такого не было, и надо было вручную делать
                const int bar_2 = foo();
                	const int& bar = bar_2;

                но это не точно.
                Ответить
            • Кресты ваши даже за такое не бют
              int& foo()
              {
              	int i =1;
              	return i;
              }

              хотя пишут ворнинг
              Ответить
        • https://wandbox.org/permlink/KXwYInUiQiiRpqCt
          в смысле не бывает
          Ответить
          • По стандарту нуллов в ссылках не бывает и конпелятор в это свято верит. clang вроде даже this на нулл не даёт проверить.
            Ответить
          • > *f2
            UB. ССЗБ.
            Ответить
            • там j123123 верно заметил, что бугор происходит не в момент, когда ты сделал *f2 при f2=0, а в момент разыменовывания ссылки.

              В С++ же нет нулл сейфти, это же не котлин. Ты обязан проверить, что указатель не указывает на говно, прежде чем покласть его результат в ссылку
              https://govnokod.ru/26958#comment575830
              Ответить
              • В крестах не бывает «разыменования ссылки». UB происходит строго в тот момент, когда ты получаешь ссылку на nullptr. После этого поведение программы становится не определено, и компилятор волен сделать тебе rm -rf /*.
                Ответить
                • >В крестах не бывает «разыменования ссылки»
                  ну ты же понял, что имелось ввиду, не?

                  Когда я пишу
                  int& foo = *some_shit_that_returns_null()
                  там под капотом в foo оказывается адрес null, и при следующем обращении случается бугор

                  Я не спорю, что UB. Просто забавно, что оно как-бы заметено под ковёр из за сахара.
                  Ответить
                  • > и при следующем обращении случается бугор
                    В этом-то и дело. Багор случается сразу же, как только ты разыменовываешь nullptr. Просто его последствия начинают проявляться позже.


                    Перефразируя j123123 (https://govnokod.ru/26809#comment575323):
                    >>> Если ты в крестах используешь какую-то сраную ебучую хуйню, типа разыменования указателя, то ты сам дурак должен соблюдать предельную осторожность с этой хуйней, и вся ответственность за segmentation fault и прочие подобные спецэффекты лежат на тебе. И нехуй в этом винить ссылки
                    Ответить
                    • #define багор СЕГФОЛТ

                      Сразу случается UB, а багор случается чуть позже (хотя наверное может и сразу случиться в теории)

                      Я так понимаю, что именно это им не нравится.
                      Ответить
        • Ещё они иммутабельные и на них нельзя арифметику чудить.

          На как по мне это сахарок с ёбнутыми значками.
          Ответить
        • >В них нуллов не бывает.

          Всё там бывает, надо просто уметь. https://wandbox.org/permlink/N8evr3fCGLXDwEMt

          Эти ссылки - просто сахарок над указателями
          Ответить
          • показать все, что скрытоvanished
            Ответить
            • Ну это оно на саму проверку жалуется. В более реальном примере может быть какая-то хуйня, типа
              int *crap = (int *)malloc(100500);
              на котором этот самый malloc обсирается и возвращает NULL, и потом в некую хуйню передается по ссылке crap[0]

              и разыменование нулевой хуйни произойдет по факту не в том месте, где вызвана хуйня shit(crap[0]) а внутри самой функции shit(), которая с этой ссылкой будет что-то делать
              Ответить
              • Ну оно же говорит, что оно может assume, а значит может все сломать, если там NULL, тоесть выкинуть например воще проверку и будет UB

                >и потом в некую хуйню передается по ссылке crap[0]
                лол, то есть можно передать уже говно, и узнать о том, что ты передал говно через три часа в другом месте?

                По сути у тебя будет ссылка на нул, да)

                Проверил. Такая хуйня скомпилировалсь, и упала. Какой багор))))
                int* foo()
                {
                	return NULL;
                }
                
                int main()
                {
                	int& bar = *foo();
                	std::cout << bar;
                	return 0;
                }
                Ответить
                • >Ну оно же говорит, что оно может assume, а значит может все сломать, если там NULL, тоесть выкинуть например воще проверку и будет UB

                  Типа да, при передаче по указателю ты можешь нормально проверить, что указатель там не NULL, а по ссылке - хуй там. Но NULL там быть все же может.

                  Ссылки - просто сахарок над указателями для заедушных питушков, чтоб поменьше * писать
                  Ответить
                  • так проверять надо ПЕРЕД тем как превращать указатель в ссылку.
                    Если ты поклал в ссылку нул, то ты сам кривой.
                    В моем примере видимо надо так
                    int* po = foo();
                    	if (po != NULL) 
                    	{
                    		int& bar = *po;
                    		std::cout << bar;
                    	}
                    Ответить
                    • Указатель тоже можно проверять ПЕРЕД передачей в хуйню. Но указатель можно проверять и внутри хуйни, поэтому я за указатели. Ссылки просто нахуй не нужны
                      Ответить
                      • показать все, что скрытоvanished
                        Ответить
                        • > а можно ссылку обратно в указатель катсануть, и проверить, на что она показывает?

                          Можно, разрешаю. https://wandbox.org/permlink/edO6vo7o3ntWfZVJ

                          https://stackoverflow.com/a/9263728
                          Ответить
                          • а, ну я тогда починил
                            #include <iostream>
                            
                            int* foo()
                            {
                            	return NULL;
                            }
                            
                            int main()
                            {
                            	int& bar = *foo();
                            	if (&bar == NULL)
                            	{
                            		std::cout << "шел бы ты";
                            	} else 
                            	{
                            		std::cout << bar;
                            	}
                            	return 0;
                            }


                            а ты грил нельзя на хуйню проверить
                            Ответить
                            • > а ты грил нельзя на хуйню проверить

                              Ну так действительно нельзя
                              Там будет такая же хуйня с варнингом на строчке if (&bar == NULL)
                              prog.cc:11:18: warning: the compiler can assume that the address of 'bar' will never be NULL [-Waddress]
                              Ответить
                              • у вижал си не будет (ну у меня нет по край мере), но линтер шланга меня отругал
                                reference cannot be bound to dereferenced null pointer in well-defined c++ code

                                То есть катсинг-то сам по себе валиден (взять адрес того, на кого указывает ссылка), а вот проверка оного на нул -- варнинг
                                Ответить
                                • > То есть катсинг-то сам по себе валиден (взять адрес того, на кого указывает ссылка), а вот проверка оного на нул -- варнинг

                                  Ну как бы да, компилятор имеет право считать, что раз у нас ссылка, то это точно что-то валидное, и NULL там быть не может.
                                  Ответить
                                  • ну то есть я ничего не починил, на самом деле

                                    компилятор имеет полное право мою проверку выкинуть, и код упадет
                                    Ответить
          • Напоминаю, что вот здесь:
            > *(int *)0
            У тебя произошло UB, и что там дальше (да и раньше тоже) происходит — никого не волнует.

            В well-formed программе на крестах nullptr в ссылке быть не может никогда.
            Ответить
            • > Напоминаю, что вот здесь:
              >> *(int *)0
              >У тебя произошло UB

              Если внимательно посмотреть, я использую особую опцию "-fno-delete-null-pointer-checks" от которой компилятор ложит хер на ту часть стандарта, которая запрещает разыменовывать NULL.

              https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
              > -fdelete-null-pointer-checks
              >
              > Assume that programs cannot safely dereference null pointers, and that no code or data element resides at address zero. This option enables simple constant folding optimizations at all optimization levels. In addition, other optimization passes in GCC use this flag to control global dataflow analyses that eliminate useless checks for null pointers; these assume that a memory access to address zero always results in a trap, so that if a pointer is checked after it has already been dereferenced, it cannot be null.
              >
              > Note however that in some environments this assumption is not true. Use -fno-delete-null-pointer-checks to disable this optimization for programs that depend on that behavior.
              >
              > This option is enabled by default on most targets. On Nios II ELF, it defaults to off. On AVR, CR16, and MSP430, this option is completely disabled.
              >
              > Passes that use the dataflow information are enabled independently at different optimization levels.

              Но видимо этот флаг не запрещает компилятору предполагать, что ссылка не может быть с NULL.
              Ответить
              • Пардон, пардон, а причём здесь вообще какие-то опции и детали реализации компилятора? Ты привёл пример невалидной программы на «C++» и почему-то обвиняешь в получившихся баграх ссылки.
                Ответить
                • Невалидная она только с точки зрения питушарского крестостандарта, а если компилятор разрешает ложить болт на него, то это уже не проблема. У меня вполне может быть какой-нибудь говноконтроллер, где прочитать или записать хуйню по нулевому указателю вполне может иметь смысл, например чтоб таблицу векторов прерываний поменять.

                  Надо просто ввести новую опцию -fallow-null-in-references
                  Ответить
                  • > а если компилятор разрешает ложить болт на него, то
                    …то ты пишешь не на «C++», а на другом языке. С тем же успехом я могу ругать сишные структуры за какие-то багры в «Cython».

                    > где прочитать или записать хуйню по нулевому указателю вполне может иметь смысл
                    По Стандарту, кстати, никакого «нулевого» указателя не существует. Конкретный адрес nullptr и NULL выбирает платформа. Синтаксис «T * ptr = 0;» является синтаксическим сахаром:
                    A null pointer constant is an integer literal (5.13.2) with value zero or a
                    prvalue of type std::nullptr_t.
                    A null pointer constant can be converted to a pointer type; the result is the null pointer
                    value of that type (6.8.2) and is distinguishable from every other value of object pointer
                    or function pointer type.

                    § 7.3.11/1 (N4842)

                    Именно поэтому читать-записывать по нулевому адресу тебе никто* не мешает:
                    int value_at_zero = *(int *)(1 - 1);


                    * При условии, что там лежит валидный объект.
                    Ответить
                    • >…то ты пишешь не на «C++», а на другом языке.

                      Только вот тогда получается так, что на настоящем «C++» не пишет вообще никто, т.к. ни один компилятор крестоговна на данный момент не реализует стандарт на 100%
                      Ответить
                      • Кстати, на полноценном «SQL» тоже никто не пишет.

                        https://modern-sql.com/standard/levels

                        > The SQL standard is huge. More than 4300 pages in its SQL:2016 incarnation. No single implementation can ever implement all features.0 Even in the early releases, such as SQL-92, the SQL standard defined different conformance levels so that vendors can claim conformance to a subset of the standard.

                        Почему кстати в стандарт крестоговна не ввели эти «conformance levels»? По-моему вполне логичный шаг.
                        Ответить
                      • Повторюсь: причём тут компиляторы? Это ты пишешь исходный код программы, а не компилятор. Если твой исходный код соответствует Стандарту, то ты пишешь на «C++», если не соответствует — то ты пишешь на каком-то другом языке с другими правилами и другими баграми. Вот и всё.
                        Ответить
                        • почему компилятор C++ даёт скомпилировать код, который типа не является C++?

                          ведь компилятор C++ не должен отвечать за другие языки.

                          в чём тут подвох
                          Ответить
                          • Потому что указанный код содержит undefined behavior. Это означает, что компилятор волен делать что угодно, включая компиляцию «Тетриса» из твоих исходников.
                            Ответить
                            • UB это же часть стандарта? Почему ты тогда говоришь, что у j123123 какой-то другой язык получился?

                              если у него реально другой язык, почему крестовый компилятор успешно компилирует такие исходники?

                              может, проблема просто в обилии UB'ов?
                              Ответить
                              • > UB это же часть стандарта?
                                Термин — да, поведение — нет.
                                3.28 [defns.undefined]
                                undefined behavior
                                behavior for which this document imposes no requirements

                                Как только в твоей программе случается UB — она перестаёт быть валидной программой на «C++», для которой Стандарт определяет какое-либо поведение.

                                > почему крестовый компилятор успешно компилирует такие исходники?
                                Потому что для программы с UB крестовый компилятор может делать что угодно!

                                > может, проблема просто в обилии UB'ов?
                                Это совершенно другая проблема.
                                Ответить
                                • ну и ну

                                  то есть компилятор C++ может взять код не на C++ и скомпилировать из него какую-то ебалу

                                  хорошо, что я на таком не пишу
                                  Ответить
                                  • Там еще есть фраза, что он не обязан при этом выдавать диагностику.
                                    Ответить
                                  • Ну да, так уж кресты устроены.
                                    Как, впрочем, и няшная сишка: там тоже есть UB и оно точно так же может через карман укусить за яйца. С другой стороны, в §J.2 (N2346) приведён полный список сишных UB, так что их можно более-менее заучить и не допускать. С третьем стороны, этот список занимает десять страниц A4.
                                    Ответить
                                    • > полный список

                                      Емнип, там офигенные вещи были в духе "название хедера не должно начинаться с цифры". Вот назовёшь хедер 1.h и получишь UB.
                                      Ответить
                                      • почему было просто не запретить хедеры с цифрами в начале?

                                        ломалось бы на этапе линковки или даже раньше
                                        Ответить
                          • показать все, что скрытоvanished
                            Ответить
                            • А это уже надо доказывать на стороне get_petuhz(). Если там корректный с++, то всё норм, ссылка не нулл.
                              Ответить
                              • показать все, что скрытоvanished
                                Ответить
                                • Тогда надо проверить на нулл. И юзать звезду только в ветке, где это условие истинно.

                                  Ну либо вместо голого указателя возвращать какой-нибудь non_null_ptr<T>. Или ссылку, лол.
                                  Ответить
                                  • показать все, что скрытоvanished
                                    Ответить
                                    • > я не знал про такую хуню

                                      Я её выдумал. Но пишется за пару минут. В конструкторе проверишь, что не нулл и бросишь исключение. А дальше можно таскать без проверок и потерь пирфоманса.
                                      Ответить
                                    • > всегда-всегда надо проверять

                                      Ну по-хорошему да. Не верить же автору сторонней либы на слово? Тем более сишные либы так сигналят об ошибке и тебе один хер проверять. А в крестах тебе голый указатель не так уж часто возвращают.
                                      Ответить
                                • > int& petuh = *get_petuhz();
                                  Если ты уверен, что get_petuhz() тебе никогда не вернёт nullptr — можешь делать так безо всяких проверок. В этом и есть смысл крестов (да и няшной тоже): ты можешь делать «опасные» операции безо всяких проверок, если считаешь, что они всегда будут корректны.

                                  Однако если твоя уверенность тебя подведёт и get_petuhz() таки вернёт nullptr — ты получишь UB, и дальше твоя программа может делать абсолютно что угодно.
                                  Ответить
                                  • ну вот и ответ Десктопу на вопрос "а зачем компилировать то, что может быть невалидным"

                                    А потому что только Программист знает, что валидно, а что нет.
                                    Он царь и бог, а не житель анально огороженной крепости с надсмотрщиком как в джава
                                    Ответить
                                    • Смех-смехом, а твоя мамка кверху мехом.
                                      а я придерживаюсь тех же взглядов. Компилятор/интерпретатор должен только проверять корректность синтаксиса, и никак не обучать тебя каким-то типизациям и, тем более, заставлять тебя удалять неиспользуемые переменные (как в "Go").
                                      Ответить
                            • мы говорили про сорцы

                              библиотека это уже бинарь
                              Ответить
                        • > Если твой исходный код соответствует Стандарту, то ты пишешь на «C++»

                          Текст стандарта крестоговна написан на английском и не является строго формализованным описанием, так что там еще хуй поймешь, можно над каким-то пунктом рассуждать как жиды над торой, что там говностандартизаторы в этом пункте имели в виду. Надо написать четкую формальную спецификацию, чтоб никаких разночтений не было, потом уже говорить, что можно писать на каком-то мифическом «C++»
                          Ответить
                          • Текст Стандарта написан на вполне себе формальном и строгом английском языке. Баги там, безусловно, бывают, но не в этом случае. Много нужно рассуждать над фразой «In particular, a null reference cannot exist in a well-defined program»?

                            > Надо написать четкую формальную спецификацию
                            Написали. Называется «Стандарт».

                            > разночтений
                            Приведи реальный пример разночтений в Стандарте.
                            Ответить
                            • > Написали. Называется «Стандарт».

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

                              > Приведи реальный пример разночтений в Стандарте.

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

                                > Могу привести реальный пример
                                Ну приведи.
                                Ответить
                                • https://habr.com/ru/company/pvs-studio/blog/495570/#comment_21463906

                                  > Давайте с memcpy, с ним проще. Я смотрю по C++17 draft, но для простоты и тех, кто не хочет грузить 1500-страничные пдфки, даю ссылки на онлайн-версию, где стандарт уже немного другой.

                                  > Так вот, 6.8/2 и /3 говорят, что вы можете делать memcpy для объектов trivially copyable типов (в частности, если они не являются подобъектами), даже если они не содержат валидного значения. И как мы видим из 11.2/1, наличие конструктора по умолчанию никак не влияет на свойство trivially copyable.

                                  > Надеюсь, этого достаточно, чтобы разобраться с memcpy.

                                  > А вот с memset всё интереснее. Он в стандарте упоминается всего несколько раз, и все эти разы — без описания семантики. Поэтому вопрос о том, что разрешено делать с memset, является совсем неочевидным. Ответ «memset в коде на плюсах использовать нельзя вообще», похоже, стандарту не противоречит.

                                  И в ответе:

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

                                  Какой багор )))

                                  Поэтому я за «Brainfuck».
                                  Ответить
                                  • Ну а где здесь разночтения-то? Уважаемый 0xd34df00d просто не разобрался. Крестостандарт нам говорит:
                                    The contents and meaning of the header <cstring> are the same as the C standard library header <string.h>.

                                    § 21.5.3/1 (N4842)

                                    Идём в «C standard», читаем:
                                    7.24.6 Miscellaneous functions
                                    7.24.6.1 The memset function
                                    Synopsis
                                    1 #include <string.h>
                                    void *memset(void *s, int c, size_t n);
                                    
                                    Description
                                    2 The memset function copies the value of c (converted to an unsigned char)
                                    into each of the first n characters of the object pointed to by s.
                                    Returns
                                    3 The memset function returns the value of s.

                                    (N2346)

                                    Всё, никаких разночтений.
                                    Ответить
                                    • А какой конкретно версии C стандарта соответствует contents and meaning хуйни <cstring> в крестоговне?
                                      Ответить
                                      • 2 Normative references [intro.refs]
                                        
                                        1 The following documents are referred to in the text in such a way that some or all of their content constitutes
                                        requirements of this document. For dated references, only the edition cited applies. For undated references,
                                        the latest edition of the referenced document (including any amendments) applies.
                                        
                                        (1.1) — Ecma International, ECMAScript Language Specification, Standard Ecma-262, third edition, 1999.
                                        [...]
                                        (1.5) — ISO/IEC 9899:2018, Programming languages — C
                                        Ответить
                                        • > ECMAScript

                                          O_o
                                          Ответить
                                          • 30.13 Modified ECMAScript regular expression grammar [re.grammar]
                                            1 The regular expression grammar recognized by basic_regex objects constructed with the ECMAScript flag
                                            is that specified by ECMA-262, except as specified below.

                                            Какой багор )))
                                            Ответить
                                            • Ну че, скоро вам жабаскрипт в крестоговно встроят в качестве препроцессора.
                                              Ответить
                                      • Да и само содержимое хедера <string.h> нихуя не описывает поведение функций memset, там просто описывается что есть такие-то функции, принимающие такие-то аргументы. Так можно еще долго доебываться

                                        Надо четко написать, что такие-то функции ведут себя точно так же, как ведут себя функции Си такого-то стандарта. А что такое meaning какого-то хеадера сишки? Просто определение функций, а что они делает - хуй знает. Это вам не крестоговно, когда там какие-то шаблоны с кодом запилены.
                                        Ответить
                                        • Ну как это не описывает, когда описывает? Я же цитату из няшного Стандарта привёл.
                                          >>> The memset function copies the value of c (converted to an unsigned char) into each of the first n characters of the object pointed to by s.
                                          Тут разве что приебаться можно к «first n characters of the object pointed to by s», но это нужно хорошенько задрочить крестовый object representation или как его, а там дохуя листов A4 формального английского, который нашему отделу чтения и парсинга обрабатывать лень.
                                          Ответить
                                          • Ну вот как мне конкретно понимать значение «contents and meaning»?

                                            contents - содержимое. Там содержатся какие-то определения функций. Т.е. инклудя <cstring> мы инклудим то же, что и в <string.h>

                                            meaning - значение. Ну т.е. смысл того что заинклужено. А смысл в хедере там такой, что вот такие-то функции есть, которые принимают такие-то аргументы и возвращает такую-то хуйню. Хедер сам по себе не описывает то, что конкретно какая функция делает. Так что надо четко сказать, что функии, определенные в таком-то хедере, делают то же самое, что они делают в сишечке такого-то стандарта.
                                            Ответить
                                            • > А смысл в хедере там такой, что вот такие-то функции есть
                                              На самом деле хорошая приёбка, но, тем не менее, Стандарт может противостоять даже таким дотошным людям!
                                              The library described in Clause 7 of ISO/IEC 9899:2018 is hereinafter called the C standard library. (1)
                                              1) With the qualifications noted in Clause 17 through Clause 32 and in C.6, the C standard
                                              library is a subset of the C++ standard library.
                                              § 2/2

                                              > Ну может это означает что-то в духе
                                              Всё есть в Стандарте.
                                              16.4.1.5 C library [structure.see.also]
                                              1 Paragraphs labeled “See also” contain cross-references to the
                                              relevant portions of other standards (Clause 2).


                                              > когда обсуждают, что именно вот конкретно этот говнопункт в крестостандарте значит, и как его надо понимать
                                              И тем не менее, после качественной раскопки Стандарта разночтений выявлено всё ещё не было. Отсутствие строгого определения слова «meaning» полностью компенсируется примечанием 1.
                                              Ответить
                                              • Блядь, как всё сложно. Именно поэтому я за "PHP".
                                                Ответить
                                                • Ну да, с тем, что кресты — монструозное раздутое говноподелие, никто и не спорил.
                                                  Ответить
                                                  • http://khpi-iip.mipk.kharkiv.edu/library/extent/dijkstra/pp/ewd952.html

                                                    Научная фантастика и научная реальность в информатике

                                                    Эдсгер В. Дейкстра
                                                    ...

                                                    Чуть раньше я упомянул плохую документацию системы как внутреннее ограничение надежности, с которой система может быть использована механически в более широком контексте. Теперь самое время указать, что привлечение технического писателя редко является выходом из положения; в сущности, это не более как признание того, что разработчики системы в некотором роде функционально безграмотны. Обычно даже целая армия технических писателей не может справиться с задачей, поскольку система становится столь сложной, что не поддается точному описанию.
                                                    Ответить
                                                    • Выдающийся пример этого явления недавно продемонстрировала Ada. Если Ada собирается выдать стандарт, желательно, чтобы он был недвусмысленно документирован. По меньшей мере две группы попытались сделать это; в результате обе выдали около 600 страниц формального текста. Это гораздо больше, чем необходимо, чтобы удостовериться в невозможности хотя бы твердо установить, что оба документа определяют один и тот же язык. Ошибка очевидной неуправляемости этих двух документов кроется ни в двух группах, составивших их, ни в принятом ими формализме, а лишь в самом языке: сами не обеспечив формального определения, могут ли его разработчики скрыть, что они предлагают неуправляемого монстра. То, что Ada уменьшит проблемы программирования и увеличит надежность наших разработок до приемлемых границ, - это лишь одна из тех сказок, в которые могут поверить только люди с военным образованием. Самое лучшее, что я могу сказать об этом, - это упорные слухи, что даже военного образования недостаточно, чтобы поддерживать веру в этот Философский Камень. Я упомянул про Ada, поскольку это замечательный пример того, на что я указывал в начале доклада: ее принятие - это политический процесс, в котором информатике, предостережения которой рассматривались как досадная помеха, не было дозволено оказывать никакого влияния. Следовательно, даже простое согласие с чьим-то обоснованным сомнением на этот счет, даже без вмешательства в контроль и намерения, становится действием с политическим душком.
                                                      Ответить
                                                      • показать все, что скрытоvanished
                                                        Ответить
                                                        • При этом в языке Ада строгая тупизация с предикатами (фактически это контрактное программирование), а слабая неявная тупизация JS заставляет срать кирпичами.
                                                          Ответить
                                                          • показать все, что скрытоvanished
                                                            Ответить
                                                            • Да, JS — вкусняшка. В деревнях и не такое ели.
                                                              Ответить
                                                            • миллионы людей пишут на JS, а на аде никто не пишут
                                                              Ответить
                                                              • показать все, что скрытоvanished
                                                                Ответить
                                                                • могу
                                                                  Ответить
                                                                  • Тем не менее, популярность языка совершенно никак не проистекает из его качества. JS в этом смысле даже вызывает больше уважения, чем пыхи и питоны, потому что у JS хотя бы есть спецификация (хотя некоторым на нее срать -- вспоминаем typeof(null)), просто люди выбирают тот язык, который сейчас популярен, и который позволяет решать нужные задачи

                                                                    Если бы в браузер была встроена ада, то все бы на ней писали, и текли, и не жужжали, и меньше было бы в мире undefined, Nan и [Object object].

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

                                                                        Хуяндл.
                                                                        Ответить
                                                                      • Оверлеи, DLL, shared objects.
                                                                        Ответить
                                                                        • мне вчера скзаали что меня ось пошлет нахуй если не сможет сразу загрузить dll
                                                                          меня наебали?
                                                                          Ответить
                                                                          • Есть много способов загрузки DLL.

                                                                            Ось сразу посылает нахуй, если DLL указана в таблице импорта. Но этот способ далеко не единственный.

                                                                            Второй способ — вызов функций LoadLibrary и GetProcAddress. Этим способом можно подгрузить DLL в любой момент и не упасть, если она не загрузится.

                                                                            А в «Линуксе» есть dlopen.
                                                                            Ответить
                                                                            • а как я узнаю интерфейс dll?
                                                                              Ответить
                                                                              • Хедер то есть обычно.

                                                                                А если на помойке нашёл - ну подизасмишь.
                                                                                Ответить
                                                                              • Я всё-таки надеюсь, что ты не собираешься вызывать функции из незнакомой DLL.

                                                                                Список символов получить можно. А вот семантику параметров функций нужно знать. В JS ты же тоже не знаешь, для чего какой аргумент у функции из чужого скрипта.
                                                                                Ответить
                                                                                • > незнакомой длл

                                                                                  Как что-то плохое. Немного дизасмишь саму длл, немного дизасмишь или дебажишь проги, которые ее юзали.

                                                                                  Если там не дичь какая-то, то часто удаётся понять суть аргументов.
                                                                                  Ответить
                                                                                  • Малость дизасмишь саму длл.
                                                                                    Малость дизасмишь проги, которые её юзали.
                                                                                    Много примеров использования получаешь.
                                                                                    Это в нашей чеховской-кибальчеховской все-все знают.
                                                                                    Ответить
                                                                                  • показать все, что скрытоvanished
                                                                                    Ответить
                                                                                • показать все, что скрытоvanished
                                                                                  Ответить
                                                                            • Ещё есть такая фишка как delayed load. Вроде дллка и прилинкована намертво, но подгрузится при первом вызове.
                                                                              Ответить
                                                                              • память экономят?
                                                                                или время запуска?
                                                                                Ответить
                                                                                • А х.з., и то и то. Ну и сама либа становится опциональной если ты аккуратен с вызовами. Можешь её уже во время работы скачать, к примеру.
                                                                                  Ответить
                                                                • Я тоже могу, если погону вернёшь.
                                                                  Ответить
                                                  • показать все, что скрытоvanished
                                                    Ответить
                                              • > На самом деле хорошая приёбка

                                                j123123 так мастерски доёбуется до С++, что из него вышел бы отличный кретостандартизатор.
                                                Ответить
                                          • Кстати да, можно еще доебаться до того, что char в крестах и char в сишке может определяться слегка по-разному, семантика указателей может быть разная, и просто так сказать типа "чтобы понять что эта хуйня делает, почитайте текст другого стандарта" - не очень хорошая идея
                                            Ответить
                                        • > Надо четко написать, что такие-то функции ведут себя точно так же, как ведут себя функции Си такого-то стандарта.
                                          Ну так там это и написано. Для каждого хедера из стандартной либы (что крестов, что няшной) есть отдельный раздел, в котором описываются meaning соответствующих функций.
                                          В крестовом Стандарте в описании <cstring> даже ссылка есть на соответствующий пункт няшного («See also: ISO C 7.24»).
                                          Ответить
                                          • > Для каждого хедера из стандартной либы (что крестов, что няшной) есть отдельный раздел, в котором описываются meaning соответствующих функций.

                                            Там же про meaning хедера говорится, а не про meaning функций.

                                            Ну и вот мы тут как раз еще один пример получили, когда обсуждают, что именно вот конкретно этот говнопункт в крестостандарте значит, и как его надо понимать, как ты и просил в https://govnokod.ru/26958#comment575919

                                            > даже ссылка есть на соответствующий пункт няшного («See also: ISO C 7.24»).

                                            Мало ли что это может значить? Ну может это означает что-то в духе "ну вот может ну нахуй это крестоговно, вот посмотрите лучше стандарт сишки, там прикольней написано".
                                            Ответить
                          • > так что там еще хуй поймешь, можно над каким-то пунктом рассуждать как жиды над торой

                            Какая однозначность )))
                            Ответить
                    • > Именно поэтому читать-записывать по нулевому адресу тебе никто* не мешает:

                      > int value_at_zero = *(int *)(1 - 1);

                      Тут кстати можно не согласиться.

                      Если хуйня «(1 - 1)» после вычислений дает то же, что и дает NULL (допустим если в хедере есть «#define NULL 0», и при этом из курса школьной математики нам известно, что «1-1=0»), то получим UB (даже если там валидный объект). Если «*(int *)(1 - 1)» дает ту же хуйню, что и «*(int *)nullptr» - получем ту же UB хуйню (даже если там валидный объект)
                      Ответить
                      • > после вычислений дает то же, что и дает NULL
                        В этом и весь смысл: (1 - 1) и 0 в контексте нулевого указателя — это разные вещи. Простой нолик-литерал — это синтаксический сахар, к нулевому адресу не имеющий никакого отношения. Поэтому из NULL == 0 вовсе не следует, что (int *)(1 - 1) — это нулевой указатель.

                        > Если «*(int *)(1 - 1)» дает ту же хуйню, что и «*(int *)nullptr» - получем ту же UB хуйню
                        А так будет только тогда, когда компилятор считает нулевой адрес за nullptr. Очевидно, если на какой-то платформе нулевой адрес валиден, то компилятор nullptr в него раскрывать не будет. Ну, если его не лалки анскильные писали, конечно.
                        Ответить
                        • Блядь, какое же ёбаное дерьмо...
                          Ответить
                          • Тяжёлое наследие сишного режима. В те стародавние времена никто не подумал, что в 0x0 может быть что-то валидное записано, вот и сделали 0 === NULL. В крестах одумались и для нулевого указателя запилили nullptr без привязки к числам, но было уже поздно, и пришлось городить такие вот говнокостыли.
                            Ответить
                            • В досовских программах адрес 0x0 вполне мог использоваться для чтения и установки вектора прерывания №0. Но в программах на ЯВУ обычно нулевой указатель не разыменовывали, а пользовались библиотечными функциями (что-то типа _dos_setvect, _dos_getvect).
                              Ответить
                              • На UEFI, к слову, там тоже лежит реалмодная IDT. И ты невозбранно можешь писнуть в нулл и сломать прошивочный видеодрайвер, если у тебя видюха со времён windows 7.

                                Какой нуллптр )))
                                Ответить
                                • Видимо, поэтому низкоуровневую питушню долгое время писали на ассемблере: так спокойнее.
                                  Ответить
                            • показать все, что скрытоvanished
                              Ответить
                              • Выше цитату привёл, про «A null pointer constant is an integer literal (5.13.2) with value zero». И вот: https://wg21.cmeerw.net/cwg/issue903
                                >>> There was a strong consensus among the CWG that only the literal 0 should be considered a null pointer constant, not any arbitrary zero-valued constant expression as is currently specified.

                                Причём до C++11 нулевым указателем считалась любое нулевое константное выражение, что приводило к такому багру:
                                void f(void *);  // #1
                                  void f(...);     // #2
                                  template<int N> void g() {
                                      f(0*N);      // calls #2; used to call #1 [gost: used to — это до C++11]
                                  }
                                Ответить
                        • показать все, что скрытоvanished
                          Ответить
                        • > В этом и весь смысл: (1 - 1) и 0 в контексте нулевого указателя — это разные вещи
                          Есть реальные примеры, где это были б разные вещи?
                          https://wandbox.org/permlink/awAHb63ePcdv8Jal - я что-то не нашел.
                          Ответить
                          • Сначала надо найти платформу где 0 != NULL. Разница только там будет, походу.
                            Ответить
                            • Даже если там 0 != NULL, каким образом «(int *)(1 - 1)» и «(int *)0» будут разными вещами?
                              Ответить
                              • 0 должен создать указатель с "пустым" значением на этой платформе (FF'ки какие-нибудь?). А 1-1 просто с нулевым. Ну если я правильно понял цитаты госта.
                                Ответить
                                • показать все, что скрытоvanished
                                  Ответить
                                • По-моему это хуйня какая-то. «0» и «(1 - 1)» это один хер с точки зрения компилятора. Пусть гост приведет убедительные доказательства со ссылками на говностандарт, что «(int *)(1 - 1)» и «(int *)0» по стандарту могут давать разную хуйню
                                  Ответить
                                  • A null pointer constant is an integer literal (5.13.2) with value zero
                                    Ответить
                                  • Я выше уже приводил цитату.
                                    >>> A null pointer constant is an integer literal (5.13.2) with value zero

                                    Ну и https://wg21.cmeerw.net/cwg/issue903 ещё.
                                    Ответить
                                    • т.е. выходит так, что такой код:
                                      void *hui;
                                      uintptr_t govno = 0;
                                      memcpy(&hui, &govno, sizeof(hui));
                                      void *muravei = 0;
                                      if(hui != muravei)
                                      {
                                        printf("sosnoole!\n");
                                      }

                                      в крестах может вывести "sosnoole!\n" ?

                                      Ну и хуйня ваши кресты.
                                      Ответить
                                      • Можно не заморачиваться.
                                        constexpr uintptr_t govno = 0;
                                        void *hui1 = reinterpret_cast<void *>(govno);  // hui1 — указатель на адрес 0x0
                                        void *hui2 = 0;  // hui2 — указатель на адрес nullptr, зависит от платформы


                                        > Ну и хуйня ваши кресты.
                                        Ну а как ещё соблюсти два условия:
                                        1) Иметь «нулевой» указатель nullptr, который на текущей платформе всегда будет невалиден;
                                        2) Иметь возможность писать в любые адреса, поддерживаемые платформой, включая 0.
                                        ?
                                        Ответить
                                        • > 1) Иметь «нулевой» указатель nullptr, который на текущей платформе всегда будет невалиден;
                                          В теории можно изобрести такую платформу, где абсолютно все указатели будут валидны, так что это условие по-сути своей - хуйня полная.

                                          > 2) Иметь возможность писать в любые адреса, поддерживаемые платформой, включая 0.

                                          Это можно было б решить какой-нибудь нестандартной хуйней, например специальным оператором разыменования или встроенной функцией, которая подразумевает что через нее можно можно и нулл разыменовать, и нихуя плохого в этом нет. Типа вместо
                                          int hui = *(* int )0;
                                          делаем
                                          int hui = __buildtin_superduper_dereference((* int )0);
                                          Ответить
                                          • > В теории
                                            А на практике такая платформа нахуй не нужна.
                                            Нулевой указатель нам нужен не для того, чтобы UB генерировать, а чтобы на него, внезапно, проверять. Вот есть у нас malloc(), она нам может вернуть либо указатель на выделенную память, либо nullptr/NULL в случае, если что-то пошло не так. Если у нас все указатели валидны — мы сосём хуй.

                                            > специальным оператором разыменования
                                            Ну и плодим никому не нужные сущности. Вместо этого разумнее было бы лишние сущности удалить, и за нулевой указатель считать только платформозависимый NULL/nullptr. Тогда мы спокойно можем писать по любому валидному числовому адресу, и никаких багров не возникает.
                                            int *null = NULL;  // «Нулевой» указатель
                                            int *zero_addr = 0;  // Адрес 0
                                            printf("%d", *zero_addr);  // Если платформа поддерживает нулевой адрес — всё заебись
                                            if (!null /*null == NULL*/) {
                                                // Выполнится всегда
                                            }
                                            if (!zero_addr /*zero_addr == NULL*/) {
                                                // Выполнится только если на текущей платформе
                                                // нулевой указатель равен нулю
                                            }
                                            Ответить
                                            • показать все, что скрытоvanished
                                              Ответить
                                              • > а может быть такая платформа, в которой невалидным является указатель из всех единичек, а нул валидный?
                                                Разумеется.
                                                Ответить
                                            • >Вот есть у нас malloc(), она нам может вернуть либо указатель на выделенную память, либо nullptr/NULL в случае, если что-то пошло не так.

                                              Эта хуйня без NULL-питухов решается - в malloc просто возвращаем структуру, которая состоит из bool и из поинтера. Если в буле false то значит malloc обосрался с выделением памяти, если в буле true то значит все норм, и из другого члена этот поинтер читаем и чето с ним делаем.
                                              Ответить
                                              • > структуру, которая состоит из bool и из поинтера
                                                Только вот есть проблема: обычно размер указателя равен размеру регистра, поэтому твоя структурка в [er]?ax не поместится. Как результат — придётся на каждый вызов любой функции, потенциально возвращающей NULL, лишний раз дрочить память, а это пиздец пирфомансу.
                                                Ответить
                                                • показать все, что скрытоvanished
                                                  Ответить
                                                • А есть ли реальные примеры частовызываемых и быстроработающих функций, которые могут потенциально возвратить NULL, переделка которых на хуйню со структурой приведет к заметному падению пирфоманса?
                                                  Ответить
                                                  • Element *findElementInHasmap(Hashmap *map, int key);  // Вызывается стотыщ миллионов раз в секунду
                                                    Ответить
                                            • >А на практике такая платформа нахуй не нужна.

                                              На практике нахуй не нужны языки, которые указывают, какие платформы нужны, а какие нет.

                                              Если взять например 8-bit AVR говноконтроллеры и почитать memory map из даташита, то там на нулевых адресах хранятся значения регистров, т.е. регистры можно прочитать из памяти таким вот образом. Если используется malloc() хуйня, то конечно же она в регистрах нихуя выделять не должна, так что для обозначения того, что malloc() обосрался, вполне можно использовать адрес 0x0000, и для этого не надо никакой хуйни с гарантировано невалидными адресами, которые разыменовывать нельзя, достаточно просто адресов, которые никакая хуйня вернуть при нормальных условиях как валидное значение указателя не должна.
                                              Ответить
                                              • > то там на нулевых адресах хранятся значения регистров, т.е. регистры можно прочитать из памяти таким вот образом
                                                И шо, все остальные адреса валидные? Прямо от 0 до 0xFFF…?

                                                > достаточно просто адресов, которые никакая хуйня вернуть при нормальных условиях как валидное значение указателя не должна.
                                                Ок, хочу функцию
                                                int *get_registers_mapping();

                                                И чтобы она на тех контроллерах, на которых маппинг регистров в память поддерживается, возвращала мне этот адрес, а на тех, где не поддерживается — об этом сообщала. Вызывать её будем триллион раз в час.
                                                Ответить
                                                • > И шо, все остальные адреса валидные?

                                                  Ну вот тут https://scienceprog.com/avr-microcontroller-memory-map/ написано что начиная с RAMEND+1 адреса идет External RAM вплоть до 0xFFFF. Если ее реально всю дозаполнить реальной памятью, то тогда похоже что да, все адреса там так или иначе будут за что-то отвечать.

                                                  >чтобы она на тех контроллерах, на которых маппинг регистров в память поддерживается, возвращала мне этот адрес, а на тех, где не поддерживается — об этом сообщала.

                                                  А нахуя? Почему б тебе не узнать о неподдерживаемости на этапе компиляции (или на этапе чтения даташитов на конкретный говноконтроллер)?
                                                  Ответить
                                                  • > avr-microcontroller-memory-map
                                                    Принимается. Да, у 16-битных (и меньше) контроллеров с лишней памятью проблемы. Их владельцам можно посоветовать либо использовать компилятор, производитель которого явно задекларировал, что в нём обращаться к NULL можно, либо хуярить асмовставки, благо из них обращаться к любым адресам никто не запрещает.

                                                    > А нахуя? Почему б тебе не узнать о неподдерживаемости на этапе компиляции (или на этапе чтения даташитов на конкретный говноконтроллер)?
                                                    Потому что надо.

                                                    Ну а вообще я к тому, что вот это:
                                                    >> достаточно просто адресов, которые никакая хуйня вернуть при нормальных условиях как валидное значение указателя не должна.
                                                    — плохое, неконсистентное решение. Если я могу прочитать данные по какому-то указателю, то почему он должен считаться невалидным?
                                                    Ответить
                                                  • показать все, что скрытоvanished
                                                    Ответить
                                        • > 1) Иметь «нулевой» указатель nullptr, который на текущей платформе всегда будет невалиден;

                                          А зачем для этого считать (void *)0 не тем же самым, что и (void *)(1-1) ? Ну пусть бы был какой-то nullptr который на одной платформе равен какому-нибудь 0xFFFFFFFF, на второй равен 0xDEADC0DE, на какой-то другой - еще какой-то хуйне, зачем его синонимировать с литералом 0? Чтоб с сишкой была совместимость?
                                          Ответить
                                          • Ну когда-то обосрались и обозначили невалидный указатель нулём. А теперь этот код боятся сломать, вот и городят какую-то хуйню.

                                            В крестах же NULLа не было в отличие от сишки.
                                            Ответить
                                        • Кстати, насчёт соответствия стандартам:
                                          #include <cstdint>
                                           
                                          int main() {
                                              constexpr uintptr_t zero = 0;
                                              // int *foo1 = (1 - 1); // error: invalid conversion from 'int' to 'int*' [-fpermissive]
                                              // int *foo2 = zero;    // error: invalid conversion from 'uintptr_t'
                                                                      // {aka 'long unsigned int'} to 'int*' [-fpermissive]
                                              int *foo3 = 0;
                                              return 0;
                                          }

                                          «GCC» Стандарт понимает правильно и выдаёт вышеуказанные ошибки. А вот «Visual Studio» последней версии на них кладёт болт и успешно компилирует все три примера. Какой багор )))
                                          Ответить
                                          • #include <cstdint>
                                            #include <iostream>
                                            
                                            void foo(void *)
                                            {
                                                std::cout << "Pointer!" << std::endl;
                                            }
                                            
                                            void foo(...)
                                            {
                                                std::cout << "...!" << std::endl;
                                            }
                                            
                                            int main()
                                            {
                                                constexpr uintptr_t zero = 1 - 1;
                                            
                                                foo(nullptr);
                                                foo(0);
                                                foo(1 - 1);
                                                foo(zero);
                                            
                                                return EXIT_SUCCESS;
                                            }

                                            «GCC» всё делает правильно и выводит «Pointer!/Pointer!/.../...»: https://wandbox.org/permlink/5HqRbFjgqNgUraDk.
                                            А вот «Visual Studio» анскильно выдаёт четыре «Pointer!»: https://gcc.godbolt.org/z/W8hdY7 (cout заменил на няшный puts, а то там пиздец килобайты асма вылезли). Какой багорище )))
                                            Ответить
                    • Да хуйня это всё, имхо.

                      Даже если у тебя какая-то платформа, где нулл можно юзать, ну положи туда какую-то структуру, на которую ты никогда не будешь брать указатели, которые могут быть невалидными. Ту же таблицу прерываний. Всяко что-то такое у тебя есть.

                      И не надо портить платформу и городить костыли на ровном месте.

                      И явный UB про разадресацию nullptr тоже можно убрать. Он ничем не отличается от любого другого указателя на мусор.
                      Ответить
                      • > И не надо портить платформу и городить костыли на ровном месте.
                        Какие костыли-то? Отдельный NULL/nullptr без привязки к конкретным числам — вполне себе заебись решение.

                        > И UB про разадресацию nullptr тоже можно убрать.
                        UB нельзя убирать, UB — это священная корова оптимизации!
                        Ответить
                        • UB про мусорные адреса - да.

                          А UB про "специальное значение", имхо, пользы не приносит. Только вред и уязвимости в духе выбрасывания проверки на нулл потому что я уже обратился.
                          Ответить
                          • показать все, что скрытоvanished
                            Ответить
                            • Ну обычно это чинят как я выше написал, какой-нибудь структурой, на которую не бывает невалидных указателей.

                              Таблица прерываний, загрузочный код и т.п.

                              Т.е. к нулю вроде и есть обращения, но их буквально пара штук на всю ось и они никогда не содержат проверку на нулл.
                              Ответить
                            • > Всё таки 0 != NULL очень сильно повышает требования к скилььности прогера
                              Зачем? Зачем?

                              obj = get_obj()
                              if obj is None:
                                  print('NullPointerException!!11')

                              Где тут повышения требования к скилльности прогера?
                              Ответить
                              • показать все, что скрытоvanished
                                Ответить
                                • > это питон же.
                                  Дык в любом языке с nullable ссылками дошли до того, что неплохо бы иметь специальное значение для пустой ссылки.

                                  > int* q = (int*)i; //вот что тут будет?
                                  С принудительным кастом — указатель на адрес 0.

                                  > if (q == NULL) //а тут что?
                                  Зависит от платформы.

                                  Проблема не в принудительном касте, проблема в неявном. По-хорошему, надо было полностью запретить неявные касты из любых чисел в указатели. Хочешь инициализировать указатель пустым значением — пиши «ptr = NULL», а не выёбывайся с «ptr = 0».
                                  Но, разумеется, теперь Боржоми пить поздно, совместимость с сишкой выкинуть не получится.
                                  Ответить
                          • > А UB про "специальное значение"
                            Дык NULL — это по определению невалидный адрес.

                            > в духе выбрасывания проверки на нулл потому что я уже обратился
                            Дык уязвимость-то будет не в выбрасывании проверки на нулл, а в самом обращении. После обращения к указателю проверка на нулл полностью бессмыслена.
                            Ответить
                            • > невалидный адрес

                              Скажем так, это просто адрес, который не может быть выделен аллокатором, описанным в стандарте (ну и не может принадлежать локалке и т.п.) Поэтому я его могу юзать как маркер пустоты или как маркер ошибки. И это удобно для всяких структур данных.

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

                              Зачем его делать пиздец-пиздец невалидным и особенным - я х.з.
                              Ответить
                              • > Зачем его делать пиздец-пиздец невалидным и особенным - я х.з.
                                Дык он и никакой не особенный. Обращение к нему — точно такое же UB, как и обращение к любому другому невалидному адресу.

                                >> В код по ошибке просочилось чтение.
                                >> А дальше пошло исполнение кода.
                                Какое исполнение-то? Чтение тебе кинуло SIGINT и всё, привет.
                                Ответить
                                • Там с другой багой совместилось, в которой нулевую страницу можно было подмапать.

                                  На то и UB. Невалидный согласно стандарту адрес вполне может быть физически валидным.
                                  Ответить
                                • Но при обращении к любому другому невалидному (согласно стандарту) адресу не взводится факт, что он теперь валидный! И не выбрасываются никакие проверки!!

                                  Почему нулл то в этом плане особенный? Потому что весь код засрали проверками на него, а теперь тормозит?
                                  Ответить
                                  • > любому другому невалидному (согласно стандарту) адресу
                                    А какие ещё адреса согласно Стандарту невалидны?

                                    > Почему нулл то в этом плане особенный?
                                    Потому что компилятор не знает и знать никак не может, какие адреса у тебя там валидные, а какие нет.
                                    int *ptr = get_hui_len_addr();
                                    printf("Hui length is %d\n", *ptr);
                                    
                                    if (ptr == (int *)0x1234) {
                                    // ...
                                    }

                                    Откуда компилятор должен узнать, что по 0x1234 у тебя ничего валидного не лежит?
                                    Ответить
                                    • Ладно, похуй. Спать пора уже: мне привиделось, что каст числа в указатель - UB.
                                      Ответить
                            • Да вот нет же, эта оптимизация превращает мелкие опечатки в реальные, практические LPE. Я тут с Линусом согласен.

                              В код по ошибке просочилось чтение. Дальше была проверка, которая остановила бы код. Но гцц ее выкинул. А дальше пошло исполнение кода.

                              Обращение к *p не должно создавать факт "p не нулл", имхо.
                              Ответить
          • Ну и чтобы не пиздеть, вот что по этому поводу говорит Стандарт:
            A reference shall be initialized to refer to a valid object or function.
            [Note: In particular, a null reference cannot exist in a well-defined program,
            because the only way to create such a reference would be to bind it to the “object”
            obtained by indirection through a null pointer, which causes undefined behavior.

            § 9.3.3.2/5 (N4842)

            Так что жаловаться на null в ссылках — это как сделать строку без \0 в конце, а потом ругать «strlen()» за то, что она падает.
            Ответить
          • Ну да, а енумы и булы - просто сахарок над интами. И в них тоже может попасть что-то левое и устроить true == false.
            Ответить
            • А хэшмапы и деревья — это просто сахарок над массивами!

              > и устроить true == false
              Кстати, в прошлом году на ГК это обсуждали: делали memcpy() в буль-буль переменную и наблюдали за весёлыми эффектами на разных компиляторах. Кажется, там ещё какой-то конпелятор проверял чётность буль-буля и 2 считал за false.
              Ответить
    • показать все, что скрытоvanished
      Ответить
      • > А что не так?
        Присвоишь ты в это поле ссылку на объект в другом скопе, он уничтожится и получишь SEGFAULT, и будешь потом долго искать в чем дело, а найдя будешь переписывать свой монолит.
        > по твоему поля всегда должны копироваться чтоли?
        умные указатели, RAII, а не это уж точно.
        Ответить
        • Чем это отличается от
          class UnitedFigure : public Figure {
              Figure *f1;
              Figure *f2;
          
          public:
              UnitedFigure (Figure *_f1, Figure *_f2) : f1(_f1), f2(_f2) {}
          
              double distance_to(const Point &p) const override {
                  return std::min(f1->distance_to(p), f2->distance_to(p));
              }
          }

          , кроме того, что ссылки тебе гарантируют null-safety?
          Ответить
          • Вероятно тем, что f2 ты можешь проверить на нул, и это будет валидно)
            А ссылку не можешь (точнее можешь, но компилятор может такую проверку выкинуть, бо будет считать, что она всегда фолс))

            Но я не защищаю эту позицию. Я не крестовик, но мне тоже нравится null safety. Во всяком случае в джавах и котлинах мне нравится знать, что поле никогда не может быть нулом, и не проверять его каждый раз, как дурак
            Ответить
        • >Присвоишь ты в это поле ссылку на объект в другом скопе, он уничтожится и получишь SEGFAULT
          С ссылками и поинтерами вообще такая проблема есть в крестах, угу.

          >умные указатели
          Ну так используй умные указатели в полях, это же можно наверное?
          Ответить
          • > умные указатели
            Умные указатели нужны тогда, когда наш класс владеет объектом (за исключением std::weak_ptr, но это специфическая штука). А когда класс должен ссылаться на какой-то объект, очевидно, приходится использовать либо указатели (и ловить багры от nullptr), либо ссылки (и ловить багры от невозможности изменить объект, на который указывает ссылка).
            Ответить
            • Если класс не владеет объектом, то ты обязан гарантировать ему, что объект не помрет, покуда инстанс твоего класса живой, а товарищу же это не нравится.
              Ответить
              • Тогда товарищу в раст.
                Ответить
                • Зачем в раст когда умные указатели есть?
                  Ответить
                  • А зачем ты ссылки полез юзать, если в твоей задаче умные указатели подходят?
                    Ответить
                  • Каким образом и зачем ты собираешься заменять умными указателями non-owning ссылки на объекты?
                    Ответить
                    • Ну сделает owning. Для данного класса какой-нибудь unique вполне сойдёт. Циклов и расшаривания вроде не предвидится.
                      Ответить
                      • Ну я так понял, что YpaHeLI_ в принципе против «ссылочных полей». Вот я и спрашиваю, как он произвольное ссылочное поле будет заменять на умный указатель.

                        > Для данного класса какой-нибудь unique вполне сойдёт.
                        А вот не факт. Я, может, не хочу ебать кучу, а хочу
                        Figure kBagpAm, kpy7;
                        UnitedFigure uf(kBagpAm, kpy7);

                        .
                        Ответить
                        • Надо сделать умные ссылки. Которые мувают объект из стека в кучу когда этот объект выходит из скопа.
                          Ответить
                          • а обжси вроде были такие умники, которые создавали блок (это обэсишное замыкание) на стеке, но при необхидности копировали его в кучу

                            Десктоп, было такое?

                            правда что именно там было на стеке яне помню
                            Ответить
                            • На самом деле, лучше научить конпелятор немного рассуждать о ссылках. Если ссылка никуда не уходит, то можно спокойно оставлять всё на стеке, пидорасить на отдельные поля в регистрах и т.п.

                              Тогда всегда пишешь как для кучи, а конпелятор сам разберётся.

                              Жабий жит вроде умеет такое. Кресты пока нет, но собираются добавить в стандарт возможность выпиливать пару new/delete.
                              Ответить
                              • да, умеет вроде

                                потому что иначе был бы ад: яхочу передать структуру из двух интов (например Point), и должен в кучу срать?

                                нувот джит умеет доказать, что ссылка не утекает и вот
                                Ответить
                                • Ну крестоконпеляторы тоже умеют такое доказывать и юзать. Но вот саму пару new/delete они пока не могут выпилить т.к. там кода пиздец дохуя и его не заинлайнить. Нужна более жёсткая семантика для new и delete, чтобы для конпелятора они были не просто парой функций которые делают произвольную хуйню.
                                  Ответить
                                  • а ты бы не охуел потом выхлоп компилятора читат?
                                    типа я такой сру в кучу, а он ESP вертит
                                    Ответить
                                    • Да норм, я уже как-то привык оптимизнутый код читать. А когда дебажный дизасм открываю, начинает тошнить от дословности.
                                      Ответить
                              • >но собираются добавить в стандарт возможность выпиливать пару new/delete.

                                Апгрейд мув-семантики?

                                Они ещё предлагают похожую технику, если конструктор+деструктор тривиальный, то объект можно копировать через memcpy.

                                Особенно поможет стд::вектору, чтобы при удвоениях делать realloc.
                                Ответить
                            • было
                              Ответить
              • И тут мы возвращаемся к тому, о чём я уже говорил…
                >>> А, ну да, это ж кресты, тут думать надо.[/color]
                Ответить
                • >кресты
                  >думать надо.

                  C++ — довольно таки примитивное, но монстровое поделие, полное исторически сложившихся нелепых нагромождений. Человек, который хорошо в нем ориентируется — это хорошее зубрилко, а не хороший программист. Умение героически преодолевать трудности, которые создает твой собственный инструмент, вместо того, чтобы решать непосредственно прикладную задачу, в современном мире ценится разве что только среди прыщавых сосок. Работодатель же это сомнительное умение не ценит, и совершенно справедливо.
                  Ответить
    • показать все, что скрытоvanished
      Ответить
    • показать все, что скрытоvanished
      Ответить
    • показать все, что скрытоvanished
      Ответить

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