Программисты на C — самый большой разделённый народ в мире?

    Сегодня, 26 апреля 2016 г., арбитражный суд Орловской области должен был решить вопрос, является ли язык программирования C иностранным языком.

    Столь необычным вопросом суд озаботился из-за Федеральной антимонопольной службы (ФАС), которая возбудилась вот на это объявление, размещённое напротив местного политеха:

    image

    ФАС посчитала это объявление рекламой, а по закону реклама на иностранном языке должна быть дублирована на русском. Руководитель компании Stork.ru Михаил Паулкин с выводами ФАС не согласился, и дело дошло до рассмотрения арбитражным судом Орловской области. Суд должен был вынести решение сегодня, но отложил заседание на 25 мая.

    Нужно заметить, что признание судом языка программирования C иностранным языком позволит программистам на C бороться за официальное признание себя в качестве малого этноса. Малый этнос — это уже не обычное профессиональное сообщество, а народ. Народ же, не имеющий своего государства, может воспользоваться правом на самоопределение, записанным во Всеобщей декларации прав человека ООН.
    Поделиться публикацией
    Комментарии 355
      +17
      Земля – крестьянам!
      Заводы – рабочим!
      Планету — хакерам!!!
        +8
        Сишникам — НСР
        (Народная Сишная Республика)
          +2
          Жители — наСильники.
            +15
            Сионисты же
              +1
              Мы так и до СС дошутимся.
                +1
                Или до СС++.
                  +5
                  Главное за C# не загреметь
                  +1
                  уже давно. не про программистов, но всё же: у нас в новостройке есть СС ИГ — совет собственников инициативная группа :)
                    +1
                    Уже.
                      +4
                      В Новосибирске есть ИГиЛ СО РАН, с отделом взрывных процессов https://ru.wikipedia.org/wiki/%D0%98%D0%BD%D1%81%D1%82%D0%B8%D1%82%D1%83%D1%82_%D0%B3%D0%B8%D0%B4%D1%80%D0%BE%D0%B4%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B8_%D0%B8%D0%BC%D0%B5%D0%BD%D0%B8_%D0%9C._%D0%90._%D0%9B%D0%B0%D0%B2%D1%80%D0%B5%D0%BD%D1%82%D1%8C%D0%B5%D0%B2%D0%B0_%D0%A1%D0%9E_%D0%A0%D0%90%D0%9D
                    0
                    Сишники
                      0
                      И сисишники
                  +1
                  Может, тогда Сишная Народная Республика? СНР даже удобнее произносить. Ну и фаны Marvell поймут :)
                    –1
                    People's Republic of C
                    Autonomous Republic of C++
                    +2
                    Линуса — в президенты!
                    Столмана — в прокуроры!
                    Балмера — в жириновские!
                      +1
                      Наделлу в главу правительства!
                        0

                        Боже упаси. Он тупо бизнесмен. Где бабло, там и он.

                        +1
                        Вспоминаются 80-е годы прошлого столетия в СССР.
                        — Долой ЕС ЭВМ (OS-360/370, аналогично сегодняшнему MS Windows)
                        — Да здравствует МОС ЕС (аналог ЮНИКС, сегодняшний Linux)
                        — Долой язык PL-1;
                        — Да здравствует С
                        Какая борьба шла за МОС ЕС (своего рода импортозамещение операционных систем).

                      +12
                      Для полноты надо рекламу на Brainfuck рядом разместить
                      +1
                      А какие варианты то перевода?
                        +7
                        *Нужна работа и есть умения – иди в Stork.
                        Ваш Кэп.
                          +6
                          Не соглашусь, там это не написано. То что вы что-то придумали, ничего не меняет.
                            +52
                            если (нужна_работа И есть_навыки) {
                                иди_в _1С
                            }
                            
                              –1
                              «В *опу Одина» :)
                                +2
                                Если НужнаРабота И ЕстьНавыки Тогда
                                ИдиВ1С;
                                КонецЕсли
                                  +3
                                  Если НужнаРабота И ЗначениеЗаполнено(Навыки) Тогда
                                  Перейти ~1С;
                                  КонецЕсли;
                                    0
                                    Не, нужно такой:

                                    если (фас ИЛИ НЕТ есть_навыки) {
                                    иди_с_миром;
                                    }
                                +20
                                На 1С
                                  +3
                                  РАПИРА же!

                                  https://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D0%BF%D0%B8%D1%80%D0%B0_%28%D1%8F%D0%B7%D1%8B%D0%BA_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F%29
                                  +5
                                  Для этого нужен дипломированный переводчик с Си на русский. Вы такого знаете?
                                    +12
                                    Увы, нет.
                                    Зато знаю множество толковых переводчиков с русского на Си
                                      +1
                                      В антивирусных компаниях таких можно найти.
                                      +3
                                      В данном контексте неизвестно что означают переменные и каковы их текущие значения и как они связаны с входными данными. Поэтому судить о том, что обозначает данная СИ-фраза не представляется возможным вообще.
                                        +2
                                        Очевидно, что данные переменные определяют, есть ли у кого-то скилл, и нужна ли ему работа. А от текущих значений зависит, пойдет ли этот кто-то на Stock.
                                        Мне почему-то все предельно ясно. Что я делаю не так?
                                          +6
                                          Вы слишком доверяете названиям переменных.

                                          int need_job = 14;
                                          struct war* have_skill = (struct war*) malloc(16);
                                          Stork: need_job += 'a';
                                          if (need_job && have_skill) {
                                          goto Stork;
                                          }

                                          Как-то так, например
                                            +3
                                            Вы их ещё про #define вспомните.
                                              +11
                                              А вы всегда так пишите, или только когда код коллега читать будет?
                                              0
                                              Все дело в том, что это лишь имена переменных, обозвать их можно как угодно.
                                                0
                                                Вот ФАС и требует обозвать их на русском.
                                                  0
                                                  Хотя, если рассуждать логически, сравнивать человеческую речь и яык программирования — некорректно. Это же набор инструций и все. Это даже близно непохоже на язык. «Языком» они были обозваны в стародавние времена, чтоб обозначить тот факт, что программист может общаться с машиной. Только это нифига не общение. Ведь общение подразумевает двустороннюю комуникацию. Но с компьютерами двусторонняя комуникация невозможна, так как все «ответы» уже заранее подготовленны программистом.
                                                    0
                                                    Если хозяин отдает команду рабам на человеческом языке, а те просто молча выполняют — это не общение?
                                                      0
                                                      Некудышный пример. Компьютер не обладает самоосознанием. А рабы каждый раз делают выбор, подчиниться или схватить наказание.
                                                        0
                                                        Нет, они же ему не отвечают, не возражают, хозяин от рабов вообще ответа не ждет, откровений тоже. Сплошной императив.
                                                      0
                                                      А разве в C допустимы unicode имена?
                                                        0
                                                        Человек выше сказал «обозвать их можно как угодно».
                                                          0
                                                          А как вы поняли, что это С, а не С++?
                                                          В С++ допустимы unicode имена, если компилятор позволит. Компилятор от MS позволяет…
                                                            0
                                                            Не знаю, как в C, в C++11 это допустимо
                                                              0
                                                              Компилятор из Visual Studio умеет юникод.
                                                              +4
                                                              Угу

                                                              #define esli if
                                                              #define poshel_v goto

                                                              esli (nuzhna_rabota && est_znaniy) {
                                                              poshel_v Stork;
                                                              }
                                                            +1
                                                            Это лишь предположение.
                                                            Быть уверенным в том, что записано в переменную и записано ли в нее что-либо мы знать не можем.
                                                              +3
                                                              Мы даже не знаем, C ли это.
                                                            +1
                                                            А каков данный контекст? И с чего вы вообще взяли, что это «СИ-фраза»? Потому что похоже?

                                                            Точно так же похоже, что словами «need_job» и «have_skill» авторы хотели обозначить «требуется работа» и «имеется навык».

                                                            И эти размышления не определяют, как реклама должна была бы выглядеть по закону. Это всего лишь ответ на ваш вопрос «Каким мог бы быть перевод?».
                                                          0
                                                          Если верно, что «требуется работа» и «имеется навык», то перейти к Сторк
                                                          +7
                                                          Надо было продублировать на 1С.
                                                            +2
                                                            Если (НужнаРабота И ЕстьНавыки) тогда
                                                            Перейти ~Stork;
                                                            КонецЕсли;
                                                              +12
                                                              Наличие кириллицы не делает этот текст написанным на русском языке. В противном случаем на КонецЕсли может возбудится уже не ФАС, а Роскомнадзор. И придётся запрещать 1С по всей стране и возвращаться к книгам бухучёта.
                                                                –1
                                                                В 1С нет аналога команды перехода goto.
                                                                  +2
                                                                  В 1C команда Перейти ~Метка это и есть goto
                                                                    0
                                                                    Упс! Действительно есть, век живи — век учись.
                                                                      0
                                                                      «Перейти» это не та вещь которую стоит знать в 1с.
                                                                        0
                                                                        Пример у них убойный с бесконечным циклом, из которого не факт, что есть выход:

                                                                        Пока Истина Цикл
                                                                        Для Каждого Элемент Из МассивЭлементов Цикл
                                                                        Если ВыполнениеУсловия(Элемент) Тогда
                                                                        Перейти ~ВыходИзДвойногоЦикла;
                                                                        КонецЕсли;

                                                                        КонецЦикла;
                                                                        КонецЦикла;
                                                                        ~ВыходИзДвойногоЦикла:
                                                                        // продолжение вычислений

                                                                          0
                                                                          Оторвать руки и «Перейти ~ВыходИзДвойногоЦикла;» заменить на «Прервать».
                                                                            +1
                                                                            Ага, только вот, Прервать из двух вложенных циклов не выведет. )

                                                                            Ну я думаю, что они оператор безусловного перехода на метку сделали для «полноты» языка. Так то они его не используют вообще.
                                                                              0
                                                                              Обфускаторы зато его широко используют, между прочим :)
                                                                          +2
                                                                          1С вообще, это не та вещь, которую стоит знать :)
                                                                            0
                                                                            Судя по размерам предлагаемых на HH зарплат — не могу так утверждать. :)
                                                                              0
                                                                                0
                                                                                Кому? Почему?
                                                                                К чему такие категоричные утверждения?
                                                                                  +1
                                                                                  Не, нормальная платформа для реализации бизнес логики.
                                                                                  +1
                                                                                  Не согласен. Как то мне попалась работа «всего на 5 минут», где нужно было добавить условие по которому из 5-ой циклической вложенности требовалось попасть на уровень второго циклы. При этом кода было на 2-3 листа — анализировать и рефакторить можно было бы целый день. Но зачем, если за это платить никто не будет, а ты видишь этот говнокод в первый и последний раз в жизни? Вот тут знание про переход по меткам очень помогло.
                                                                            0
                                                                            скорее «Перейти ~куда_угодно_только_не_в_сторк»
                                                                            0
                                                                            Тоже была такая мысль. Ну а вообще вариантов то много: РАПИРА, Кумир… Если поискать, то еще можно чего-нибудь найти.
                                                                            В конце-концов, что мешало им сделать просто блок-схему! :)
                                                                            –1
                                                                            Разве одного языка достаточно для того что бы считать себя единым народом?
                                                                            Разве главное не происхождение?
                                                                              +6
                                                                              «Этничность можно представить как форму общественной организации культурных различий, состоящей из тех характеристик, которые сами члены этнической общности считают для себя значимыми и которые лежат в основе их самосознания. К этим характеристикам относится также обладание одним или несколькими общими названиями, общие элементы культуры, представление об общем происхождении и, как следствие, наличие общей исторической памяти.…

                                                                              Определение этничности строится также на основе культурной самоидентификации этнической общности по отношению к другим общностям (этническим, общественным, политическим), с которыми она находится в фундаментальных связях.» https://ru.wikipedia.org/wiki/Этнос

                                                                              «Этнос — исторически сложившаяся этническая общность — племя, народность, нация.

                                                                              Нация — исторически сложившаяся устойчивая общность людей, образующихся в процессе формирования общности их территории, экономических связей, литературного языка, особенностей культуры и духовного облика.» С. И. Ожегов
                                                                                +43

                                                                                Общей исторической памятью, надо полагать, является git log ядра linux?

                                                                                  +13
                                                                                  Это будет религиозной литературой.
                                                                                    0
                                                                                    Ветхий завет. Бытиё. Наши дни.
                                                                                    А всех программистов на c-like языках будем считать сектантами :)
                                                                                    +2
                                                                                    Общей исторической памятью являются Кен Томпсон и Деннис Ритчи, за консолью PDP-11.

                                                                                    image
                                                                                    +1
                                                                                    Признаю: все эти определения можно пусть и с оговорками примерить на си разработчиков. Но ведь скажем если я выучу татарский язык — я ведь не стану татарином?=)
                                                                                      +3
                                                                                      Вы можете быть татарином и не зная татарского языка.

                                                                                      Вообще, в современном мире национальность определяется самоидентификацией. Вы сами должны определиться (если хотите), кто вы больше — русский или сишник.

                                                                                      При переписи населения вас просто попросят указать, кто вы по национальности, не вдаваясь в подробности национальностей бабушек или дедушек, а если вы не захотите говорить переписчику свою национальность, настаивать не имеют права.
                                                                                    0
                                                                                    Там всё слегонца сложнее.
                                                                                    http://blogovodoved.livejournal.com/4059.html
                                                                                      0
                                                                                      Если про образование народа по языкопрограмистскому признаку не писали в фантастическом произведении, то это маловероятно.
                                                                                      Напишите, если знаете такие произведения.
                                                                                      +2
                                                                                      Если арбитражный суд откажет в иске, то надо подать групповую аппеляцию в международный суд по правам человека. Даже до ООН дойдём!
                                                                                        +47
                                                                                        Я думаю, это все из-за goto в коде.
                                                                                          +2
                                                                                          На самом деле не хватает
                                                                                          have_skill = cpp_skill == excelent && boost_skill > beginner && !windows_only;

                                                                                            +5
                                                                                            Это уже за разжигание, пойдет… и не по гражданскому кодексу.
                                                                                          –24
                                                                                          GOTO!!! Си!!! Карл!!!
                                                                                          image
                                                                                            +31
                                                                                            Расслабься и открой исходники ядра линукса.
                                                                                              +11
                                                                                              вот из за таких как вы из повершела убрали GOTO. и для того чтобы выскочить из одного цикла в другой приходится мудрить переменные и проверки.
                                                                                              • НЛО прилетело и опубликовало эту надпись здесь
                                                                                                  0
                                                                                                  убрали ещё на этапе разработки.
                                                                                                    –1
                                                                                                    Вот это поворот
                                                                                                    вот из за таких как вы из повершела убрали GOTO
                                                                                                    убрали ещё на этапе разработки
                                                                                                    Я не знаком с данным продуктом, но по факту получается, что GOTO нет в первоначальном релизе… т.е. по задумке авторов изначально оператор безусловного перехода не предусмотрен. Вам не кажется, что «такие как я» тут как бы не причем, т.к. GOTO не было в релизе от слова совсем. А то я уже стал сыпать голову пеплом… а оказалось вон оно как.
                                                                                                      0
                                                                                                      так ведь разработчики и относятся к ненавистникам goto
                                                                                                      в замен дали break :label
                                                                                                      Но както через жо
                                                                                                      В Windows PowerShell иметь метки могут только ключевые слова цикла, такие как Foreach, For, While.

                                                                                                      в результате из цикла можно выскочить только в начало другого цикла или в конец этого.
                                                                                                      Экспресс в середину цикла? да кому оно надо подумали они.
                                                                                                        0
                                                                                                        так ведь разработчики и относятся к ненавистникам goto
                                                                                                        Вы напрасно ярлыки развешали. Я не ненавистник, я его просто не использую в си, а студентам просто не говорю, что так можно. При этом в проектах на асме goto jmp — это наше все.
                                                                                                        Приведите пример безусловного перехода в середину цикла на си… а то у меня мозг ломается от такой задачи
                                                                                                          0
                                                                                                          не фанат С но вроде компилируется в билдере
                                                                                                          просьба сильно не пинать мне ассемблер роднее чем С
                                                                                                          #include <stdio.h>
                                                                                                          int main(void)
                                                                                                          {
                                                                                                            int P;
                                                                                                            int PP;
                                                                                                            int count=0;
                                                                                                            int H=50000000;
                                                                                                            int N=61000000;
                                                                                                          
                                                                                                            if (H%2==0) {H++;}
                                                                                                            while (H<=N)
                                                                                                            {
                                                                                                             P=1;
                                                                                                             PP=round(sqrt(H));
                                                                                                             do
                                                                                                             {
                                                                                                          	P=P+2;
                                                                                                          	if (H%P==0) {goto E;}
                                                                                                             }
                                                                                                          	while (P<=PP);
                                                                                                             count++;
                                                                                                          E: H=H+2;
                                                                                                            }
                                                                                                          
                                                                                                          	 printf( "%d\n", count );
                                                                                                          	 getchar();
                                                                                                          	return 0;
                                                                                                          }
                                                                                                          

                                                                                                            0
                                                                                                            Я думал, что в си через goto обрабатывают ошибки.
                                                                                                            Как вы их обрабатываете без goto?
                                                                                                              0
                                                                                                              В С++ есть try-catch блоки, из того что встречал. Не знаю, имеется ли такой механизм в C.
                                                                                                              По факту ошибки выполняется throw(чё произошло) и ловится в catch. Дальше уже пляшем.
                                                                                                              Возможно, есть что-то ещё.
                                                                                                                +1
                                                                                                                В Си нет try, catch и исключений.
                                                                                                                  +1
                                                                                                                  … но есть setjmp() и longjmp().
                                                                                                                    +1
                                                                                                                    По форме (а не по содержанию) ничем не отличается от goto: прыгнуть туда-то.
                                                                                                                    Т.е. longjmp ближе к goto, чем к генерации исключения.
                                                                                                    –1
                                                                                                    Благодаря этому коментарию, вспомнил что в php есть такая вот штука (http://php.net/manual/ru/control-structures.break.php). В сам break можно передать параметр, который укажет, через сколько уровней цикла можно перепрыгнуть. Добавляет приятный сахарок в синтаксис и отменяет необходимость в «флажках».
                                                                                                      +1
                                                                                                      Появление необходимости в флажках сигнализирует о том, что тут что-то не так.
                                                                                                        0
                                                                                                        break с упоминанием какой именно цикл прервать??? И как такое читать потом?
                                                                                                      +17
                                                                                                      Ничего страшного в GOTO нет, тем более в Си. Очень часто его использование очень оправдано.
                                                                                                        +4
                                                                                                        Нам, излишне наверное категоричный, преподаватель запретил использовать goto. Поначалу было не комфортно, но потом мозг перестроился и с тех пор уже 20 лет как отсуствие goto в программёрской практике совершенно не напрягает. Я уже про него и забыл.
                                                                                                        Могу осторожно согласиться, что я просто не встречался с задачами, где без goto никак.
                                                                                                          +1
                                                                                                          Вот вам такая выскочить из середины одно цикла в середину другого. Обойтись можно но надо мудрить кучу if else.
                                                                                                            +9
                                                                                                            Смутно представляю, когда может появиться такая необходимость. Уверен, что в таких случаях код можно переписать более красиво.
                                                                                                              +1
                                                                                                              Я, честно говоря, плохо понял что имел ввиду Foolleren, но типовой случай использования goto в C/С++ это выход из двойного цикла (например если мы гуляем по дву-/трехмерной таблице и дошли до точки).
                                                                                                              Википедия
                                                                                                              for implementing multi-level break and continue if not directly supported in the language; this is a common idiom in C. Ссылка на википедию с ссылкой на источник


                                                                                                              Второй способ описан ниже и применим только для C, но не для C++.
                                                                                                                0
                                                                                                                bool go_out = false;
                                                                                                                for(int x = -1024; (x <= 1024) && (!go_out); x++){
                                                                                                                    for(int y = -1024; (y <= 1024) && (!go_out); y++){
                                                                                                                        // any operations
                                                                                                                        ...
                                                                                                                        // block end
                                                                                                                        if(m[x][y] == 'X'){
                                                                                                                            go_out = true;
                                                                                                                        }
                                                                                                                    }
                                                                                                                }
                                                                                                                

                                                                                                                Чем не решение? Случай синтетический, лично не доводилось использовать такие конструкции.
                                                                                                                  +2
                                                                                                                  break'ами мне кажется быстрее будет, чем на каждой итерации проверять состояние переменной.
                                                                                                                    +1
                                                                                                                    На ум приходит сразу 4 решения:

                                                                                                                    1. Обернуть код в функцию (предпочтительно).
                                                                                                                    2. Написать двумерный итератор (тоже хороший вариант).
                                                                                                                    3. После go_out поставить break, и проверять условие только во внешнем цикле.
                                                                                                                    4. Заменить go_out на x = 1025, y = 1025 (крайне нежелательно).
                                                                                                                      +5
                                                                                                                      Нужно просто вынести этот код в функцию и return'ом вернуть найденный элемент.
                                                                                                                        +5
                                                                                                                        Тем что это медленнее.
                                                                                                                        Goto — это нативная команда ассемблера, JMP и куча нативных Jxx, из этого состоит весь компилированный код.
                                                                                                                        Вместо этого в твоём примере тратим память на абсолютно ненужную переменную, на доступ к памяти, на чтение памяти каждый раз в этой миллионной интерации, вместо того чтобы сделать один goto и съэкономить миллиадры циклов процессора. Даже если go_out будет лежать в регистре, это всё равно не бесплатная операция проверки.

                                                                                                                        А потом удивляемся, почему у нас всё везде тормозит на 8 ядрах и 4х гигагерцах, потому что каждый уровень разработчиков абстракции побоялся где-то чуть оптимизировать код и побоялся «богомерзкого» нативного goto, якобы «кто-то сказал что так нельзя». Эти же люди бояться писать без «ооп», делают фабрики фабрик даже там где это не нужно и совсем не думают о производительности.
                                                                                                                          –1
                                                                                                                          Если у вас " тормозит на 8 ядрах и 4х гигагерцах" и производительность упирается в проверки флагов и серьезно улучшается от внедрения повсеместно goto, тут что-то у вас не так.
                                                                                                                            0
                                                                                                                            Не согласен. Из-за частого обращения будева переменная будет висеть в кэше и время доступа будет крайне малО.
                                                                                                                              0
                                                                                                                              и я не согласен, закидывание переменных в регистры в зависимости от процессора даёт в худшем случае 1% буста в лучшем 20+%. профилирование кодека divx выявило, что вытаскивание переменных из стека занимает большую часть времени функции.
                                                                                                                            0
                                                                                                                            А подскажите почему тут нельзя использовать while?
                                                                                                                            0
                                                                                                                            Как вариант можно использовать try-catch. С++ плоховато знаю, но принцип понятен.
                                                                                                                            говнокод на C#
                                                                                                                            int i, j, k;
                                                                                                                            
                                                                                                                            try
                                                                                                                            {
                                                                                                                                for (i = 0; i < 100; i++)
                                                                                                                                {
                                                                                                                                    for (j = 0; j < 100; j++)
                                                                                                                                    {
                                                                                                                                        for (k = 0; k < 100; k++)
                                                                                                                                        {
                                                                                                                                            if (k == 50)
                                                                                                                                            {
                                                                                                                                                throw new IndexOutOfRangeException();
                                                                                                                                            }
                                                                                                                                        }
                                                                                                                                    }
                                                                                                                                }
                                                                                                                            }
                                                                                                                            catch (IndexOutOfRangeException) {}

                                                                                                                              +8
                                                                                                                              а ничего, что механизм исключений очень дорогой и является наихудшайшим вариантом из всех возможных?
                                                                                                                                +1
                                                                                                                                Ну, это понятное дело. Но, если совсем вообще никак, то как вариант. =)
                                                                                                                                  0
                                                                                                                                  а ничего, что иногда выйти из вложенных циклов нужно всего один раз. В таком случае дороговизна генерации исключения и его отлова роли не играет.
                                                                                                                                    +1
                                                                                                                                    При этом затраты на обработку исключения могут быть на порядок больше, чем собственно выполнение цикла.
                                                                                                                                      0
                                                                                                                                      А если таких узких мест будет несколько?
                                                                                                                                        0
                                                                                                                                        А чем исключение лучше goto? В ситуации, когда надо выйти из вложенного цикла, и то, и то — костыль. Но goto костыль дешевый и логичный. А генерация исключения — дорогой и нелогичный.
                                                                                                                                          0
                                                                                                                                          Исключения лучше чем goto потому что корректно уничтожают автоматические переменные.
                                                                                                                                          А goto просто прёт напролом.
                                                                                                                                          Насколько я понимаю.
                                                                                                                                            0
                                                                                                                                            Нет, goto тоже их все корректно уничтожит.
                                                                                                                                            On exit from a scope (however accomplished), destructors (12.4) are called for all constructed objects with automatic storage duration (3.7.2) (named objects or temporaries) that are declared in that scope, in the reverse order of their declaration.
                                                                                                                                              +1
                                                                                                                                              А там куда прыгнули — так же всё создастся в порядке появления в коде, как я понимаю?
                                                                                                                                              Тогда это не просто jmp куда-то на метку, получается, а сложная конструкция.
                                                                                                                                                0
                                                                                                                                                It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps from a point where a local variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has POD type and is declared without an initializer.
                                                                                                                                                  +1
                                                                                                                                                  В общем, не всё так просто с этими goto.
                                                                                                                                                  Мутная тема. По крайней мере в С++, где не только POD.
                                                                                                                                                    0
                                                                                                                                                    В С++ вообще нету простых тем :-Р

                                                                                                                                                    Но по крайней мере, компилятор вам не даст «запрыгнуть» внутрь блока в обход инициализации переменных. Или переменные инициализируются по умолчанию (некоторые компиляторы, включая MSVC++, в «нестрогом» режиме это разрешают), или будет ошибка компиляции.
                                                                                                                                  0
                                                                                                                                  Когда я полез за тем что бы узнать чем вообще заменить GOTO в повершеле, наткнулся на такой кейс
                                                                                                                                  раскрашивание логов в html, мне он нужен был для совершенно не нормального применения — сравнить скорость работы алгоритма в разных ЯП ну и бонусом в повершеле.
                                                                                                                                  также призывается comargo
                                                                                                                                  +1
                                                                                                                                  Волосы дыбом встают от такого алгоритма :)
                                                                                                                                    0
                                                                                                                                    Угу, без комментариев понять, что происходит совсем не просто, за это собственно GOTO и не любят, но местами с ним всё же проще чем без него.
                                                                                                                                      0
                                                                                                                                      Вы так или иначе условие выхода из цикла будете проверять через if или case. И если вы прервёте выполнение цикла по break или продолжить очередной цикл по continue не проходя до конца весь цикл, вы получите такой же функционал, который прекрасно работает без goto и значительно облегчает понимание алгоритма и его отладку.
                                                                                                                                        0
                                                                                                                                        Да выход в таком случае будет всё равно через if, но когда надо прыгнуть в середину другого цикла, без goto получается проблема.
                                                                                                                                          0
                                                                                                                                          Такой же if но уже в другом цикле. Разве нет? Ведь цикл у всё равно нужны условия начала, окончания цикла. Не всё ли равно начинать в начале цикла проверку какую часть выполнять или в середине?
                                                                                                                                            0
                                                                                                                                            Надеюсь, я правильно понял семантику требования «прыгнуть в середину другого цикла».
                                                                                                                                            private void doFirstCycle() {
                                                                                                                                              int j;
                                                                                                                                              for (j=0; j<100; j++) {
                                                                                                                                                doYourJob();
                                                                                                                                                if (this.haveToBreak) {
                                                                                                                                                  doSecondCycle(3, 200);
                                                                                                                                                  break;
                                                                                                                                                }
                                                                                                                                              }
                                                                                                                                            return;
                                                                                                                                            }
                                                                                                                                            
                                                                                                                                            private void doSecondCycle(from, to) {
                                                                                                                                              int i;
                                                                                                                                              for (i=from; i<to; i++) {
                                                                                                                                              doAnotherJob();
                                                                                                                                              return;
                                                                                                                                            }
                                                                                                                                            


                                                                                                                                            В нужном месте той огромной нечитаемой функции, из одного из циклов которой нужно прыгать в середину другого, вместо цикла вставляете вызов функции. Заодно и читаемость повысится.
                                                                                                                                              0
                                                                                                                                              когда я говорил про середину, то имел в виду совсем середину — не кратную
                                                                                                                                              — надо начать с doAnotherJob_2();
                                                                                                                                              private void doSecondCycle(from, to) {
                                                                                                                                              
                                                                                                                                                int i;
                                                                                                                                              
                                                                                                                                                for (i=from; i<to; i++) {
                                                                                                                                              
                                                                                                                                                doAnotherJob_1();
                                                                                                                                                doAnotherJob_2();
                                                                                                                                              
                                                                                                                                                return;
                                                                                                                                              }
                                                                                                                                              
                                                                                                                                                0
                                                                                                                                                Можно задать выполнение нужных частей кода битовой маской или значением enum'а. Предполагаем, что в следующей итерации цикла мы выполним тело целиком (а с goto так и выйдет); в этом месте мой мозг начинает понемногу плавиться.
                                                                                                                                                private enum dirtyCycleJumper { 
                                                                                                                                                fromFirst, 
                                                                                                                                                fromSecond
                                                                                                                                                }
                                                                                                                                                
                                                                                                                                                private void doSecondCycle(int from, int to, dirtyCycleJumper startFrom) {
                                                                                                                                                
                                                                                                                                                  int i;
                                                                                                                                                
                                                                                                                                                  for (i=from; i<to; i++) {
                                                                                                                                                  switch (startFrom) {
                                                                                                                                                case fromFirst:  doAnotherJob_1(); 
                                                                                                                                                case fromSecond:  doAnotherJob_2();
                                                                                                                                                }
                                                                                                                                                startFrom = dirtyCycleJumber.fromFirst;
                                                                                                                                                }
                                                                                                                                                return;
                                                                                                                                                }
                                                                                                                                                
                                                                                                                                                
                                                                                                                                                

                                                                                                                                                Вызываем doSecondCycle(3, 200, dirtyCycleJumper.fromSecond).
                                                                                                                                                С такими требованиями, действительно, goto будет удобнее. Но случай какой-то уж больно маргинальный.
                                                                                                                                                  –1
                                                                                                                                                  случай действительно очень редкий, и очень хорошо подходит чтобы запутать предсказатель ветвлений старого процессора, например разница между феном 1100 и вишерой 9590@ оказалась 8 раз при выполнении в 1 поток при выходе/входе через goto, интеловских свежаков для сравнения к сожалению нет,
                                                                                                                                                  когда руки дойдут сравню различные способы обойти goto где он действительно просится( запрыгнуть в середину цикла), но беглый взгляд подсказывает что goto должен отработать быстрее вызова функции.
                                                                                                                                            0
                                                                                                                                            Надеюсь, я правильно понял семантику требования «прыгнуть в середину другого цикла».

                                                                                                                                            private void doFirstCycle() {
                                                                                                                                            int j;
                                                                                                                                            for (j=0; j
                                                                                                                                      0
                                                                                                                                      Написанный в прошлом такой свой код (с кучей IF и прыжками из одной части в другую в гигантском цикле) сейчас считаю примером того как не надо было писать.
                                                                                                                                      И живет он теперь почти как ИИ, хрен знаешь что выкинет в следующий раз.
                                                                                                                                      Лучше переписать так чтобы в принципе не нужно было из середины цикла кудато прыгать
                                                                                                                                        0
                                                                                                                                        ну вот смотрите у нас есть условия которые проверяются для какого то массива, если проходит, то проверяем другие условия во втором цикле, и вот тут если не проходит надо сделать первое и второе если не проходит то только второе.
                                                                                                                                        можно сделать goto на второе
                                                                                                                                        или сделать ещё одну переменную и break`ом оборвать первый цикл, а потом пройтись по куче if, когда количество итераций плавно так уходит за 6 лямов, каждый if в цикле делает вас печальнее.
                                                                                                                                          +1
                                                                                                                                          А чем Вас return не устроит, с нужным разбиением на функции, как раз вывалитесь где надо?
                                                                                                                                            0
                                                                                                                                            в си функции по умолчанию передают параметры через стек, работа со стеком не на всех процессорах происходит без потерь для производительности.
                                                                                                                                              +3
                                                                                                                                              Я думаю, любой нетривиальный компилятор С сделает одиноко вызываемую функцию inline'овой, а все return'ы из нее заменит на jmp'ы, которые, по сути, те же goto.
                                                                                                                                                0
                                                                                                                                                как нибудь проверю.
                                                                                                                                                0
                                                                                                                                                Способ передачи параметров в Си все же лучше рассматривать с точки зрения платформы, а не языка. В X64 первые 4 или 5 аргументов без вариантов уйдут через регистры.
                                                                                                                                                  0
                                                                                                                                                  Т.е. там va_args не такой, как на x86?
                                                                                                                                          0
                                                                                                                                          В Джаве нет goto, а для выхода из нескольких циклов есть типа такого:
                                                                                                                                          a: while(true) {
                                                                                                                                           while(true) {
                                                                                                                                            if (Math.random() < 0.5) {
                                                                                                                                             break a;
                                                                                                                                            }
                                                                                                                                           }
                                                                                                                                          }
                                                                                                                                          
                                                                                                                                            +1
                                                                                                                                            Ну, goto было когда-то, но потом его выкинули. До сих пор goto — зарезервированное ключевое слово. Да и из байткода его не выкинешь :)
                                                                                                                                          +9
                                                                                                                                          Основной паттерн использования goto в современном си — досрочный выход из функций с корректным освобождением ресурсов. Возможно у вас предмет называется c++, в котором использовать goto действительно не желательно. В си — это абсолютно нормальное явления — возьмите любой крупный сишный проект.
                                                                                                                                            +1
                                                                                                                                            Учили-то мы C, хотя последние лет 15 программирую в основном на C++.
                                                                                                                                            Но первые лет 5 и после тогда отвлекался на С. Модуль ядра линукс даже помнится писал.
                                                                                                                                            Но нигде алгоритм не упирался в goto. Так, что прям без него вот ну никак.
                                                                                                                                            И даже на c++ не всегда RAII использую. Но обхожусь без goto и, повторю, ни разу не вспоминал про него в духе: эх, тут goto просится.
                                                                                                                                            +8
                                                                                                                                            Есть прекрасный паттерн использования goto — выход из функции по ошибке с очисткой ресурсов. Например:
                                                                                                                                            int do_or_fail(void)
                                                                                                                                            {
                                                                                                                                                FILE *f1, *f2, *f3;
                                                                                                                                                int retval = 0;
                                                                                                                                                if(!(f1=fopen("aaa.txt","r")))
                                                                                                                                                    return 0;
                                                                                                                                                if(!(f2=fopen("bbb.txt","r")))
                                                                                                                                                    goto cleanup_f1;
                                                                                                                                                if(!(f3=fopen("ccc.txt","r")))
                                                                                                                                                    goto cleanup_f2;
                                                                                                                                                /* ... do something with the files .... */
                                                                                                                                                retval = 1;
                                                                                                                                            cleanup_f3:
                                                                                                                                                fclose(f3);
                                                                                                                                            cleanup_f2:
                                                                                                                                                fclose(f2);
                                                                                                                                            cleanup_f1:
                                                                                                                                                fclose(f1);
                                                                                                                                                return retval;
                                                                                                                                            }

                                                                                                                                            Без него при каждом открытии файла был бы иф с кучей команд освобождения ресурсов и возвратом по ошибке. При этом код освобождения ресурсов дублируется, что загромождает программу. А еще в таком коде легко допустить ошибку.
                                                                                                                                              –5
                                                                                                                                              Как только люди не извращаются, лишь бы на нормальном C++ с RAII не писать.
                                                                                                                                                +5
                                                                                                                                                И как Вы на «нормальном C++ с RAII» напишете модуль ядра линукса?
                                                                                                                                                  –8
                                                                                                                                                  А это уже вопрос религии линуксоидов, а не технологии. Как-то вот в Windows и MacOs это можно сделать, а красноглазым чисто Эго не позволяет до С++ опуститься.
                                                                                                                                                    +1
                                                                                                                                                    Ядро Windows тоже на «голом» C написано. И большая часть драйверов, работающих в режиме ядра — тоже. Боюсь, что, даже если где-то в ядро можно влезть с C++ — то там будут ограничения по используемым возможностям, например — отсутствие полной поддержки исключений.
                                                                                                                                                      +1
                                                                                                                                                      Есть нюансы, кто же спорит. Но уж такую мелочь как RAII всё-же потянет.
                                                                                                                                                        0
                                                                                                                                                        RAII без исключений невозможно, а исключения — один из «тяжелых» механизмов C++, который в контексте ядра ОС может не поддерживаться или поддерживаться ограниченно. Например, для обычного кода использование исключений может быть возможно, а для всяких ISR и DPC — нет.

                                                                                                                                                        Также не стоит забывать, что обстановка в ядре ОС сильно отличается от обстановки в user-space. В user-space у вас обычно есть потоки, и каждый из них выполняет какой-то длинный код, захватывая ресурсы и освобождая их. Здесь RAII работает хорошо. А в ядре у вас в основном callbacks (в числе которых ISR и DPC), короткие функции, которые должны быстро отработать и выйти. Захваченные ресурсы зачастую удерживаются между вызовами этих функций, а вызваны они могут быть в контексте разных потоков и процессов. Так что RAII в чистом виде здесь имеет ограниченное применение, как, впрочем, и вышеприведенный паттерн с goto.
                                                                                                                                                          +3
                                                                                                                                                          А почему RAII невозможно без исключений? o_O
                                                                                                                                                            0
                                                                                                                                                            А как вы будете сообщать об ошибке из конструктора? Сообщать об ошибках инициализации членов класса или базовых классов? Уничтожать уже созданные члены?

                                                                                                                                                            Какие-то костыли, конечно, можно придумать, но от этого вся красота и удобство RAII сходят на нет.
                                                                                                                                                              0
                                                                                                                                                              Суть RAII заключается не в том, чтобы бросить исключение в конструкторе.

                                                                                                                                                              А по вашему вообще ООП без исключений невозможно получается?
                                                                                                                                                                +1
                                                                                                                                                                Суть RAII заключается не в том, чтобы бросить исключение в конструкторе.

                                                                                                                                                                Я не говорил, что «бросить исключение в конструкторе — это суть RAII».

                                                                                                                                                                Но возможность бросить исключение в конструкторе является критической для реализации RAII так, чтобы код получался красивым и корректным. Поясните пожалуйста, как можно реализовать RAII без исключений в конструкторе?
                                                                                                                                                                А по вашему вообще ООП без исключений невозможно получается?

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

                                                                                                                                                                  Ну и если могут быть ошибки, можно оставить проверку ошибок для отдельных функций, а не кидать исключения.
                                                                                                                                                                  Конструктор открыл файл.
                                                                                                                                                                  Внешний код вызвал функцию проверки всё-ли в порядке.
                                                                                                                                                                  Файловые потоки stl c++ так и работают.
                                                                                                                                                                    +1
                                                                                                                                                                    В общем случае, ошибки при захвате ресурса может и не быть.

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

                                                                                                                                                                    И тогда RAII превращается в адъ.

                                                                                                                                                                    Мы в данной ветке обсуждаем паттерн goto для досрочного возврата из функции с очисткой ресурсов. Выше была приведена реализация на C для случая открытия трех файлов. Те, кто говорил здесь о RAII, имели в виду, что с помощью RAII эта задача решается проще. С этим можно согласиться. Вот пример реализации с помощью RAII:
                                                                                                                                                                    class RaiiFile
                                                                                                                                                                    {
                                                                                                                                                                    public:
                                                                                                                                                                        RaiiFile(const char* filename): f(fopen(filename,"r")) {if(!f) throw std::runtime_error("File open failed");}
                                                                                                                                                                        ~RaiiFile() { fclose(f); }
                                                                                                                                                                    private:
                                                                                                                                                                        FILE* f;
                                                                                                                                                                    }
                                                                                                                                                                    
                                                                                                                                                                    void do_or_fail(void) // Throws an exception on failure
                                                                                                                                                                    {
                                                                                                                                                                        RaiiFile f1("aaa.txt");
                                                                                                                                                                        RaiiFile f2("bbb.txt");
                                                                                                                                                                        RaiiFile f3("ccc.txt");
                                                                                                                                                                        /* ... do something with the files .... */
                                                                                                                                                                    
                                                                                                                                                                        // The files will be correctly closed on return or exception anywhere in this function
                                                                                                                                                                    }
                                                                                                                                                                    

                                                                                                                                                                    Попробуйте сделать то же самое без исключений в конструкторах. Потом сравните с вариантом на C с goto.
                                                                                                                                                                      0
                                                                                                                                                                      Вы не путайте выделение ресурса с его захватом.
                                                                                                                                                                      И память может быть уже выделена и уже после отдаётся для управления RAII-объекту.
                                                                                                                                                                      И мьютекс уже заранее создан и отдается на блокирование RAII-объекту.
                                                                                                                                                                        0
                                                                                                                                                                        Вы не путайте

                                                                                                                                                                        Уважаемый, пожалуйста не используйте в разговоре со мной такой поучительный тон. Еще неизвестно, кто из нас что путает.
                                                                                                                                                                        И мьютекс уже заранее создан и отдается на блокирование RAII-объекту.

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

                                                                                                                                                                        Ну и даже если вы найдете примеры, когда ошибка в конструкторе возникнуть не может — все же это не опровергает, что при захвате, выделении, или каких угодно операций в отношении ресурсов чаще встречается ситуация, когда может возникнуть ошибка, чем наоборот. И пример с goto, с которого началось обсуждение, как раз возник из задачи обработки ошибок. К чему вы вообще сюда приплетаете участки кода, где ошибок возникать не может?

                                                                                                                                                                        Вам выше был задан вопрос, можете ли вы реализовать обработку ошибок на базе RAII, но без исключений. И привести пример для сравнения. Вопрос остался без ответа. Не можете?
                                                                                                                                                                          0
                                                                                                                                                                          Если Вы пишете:

                                                                                                                                                                          «В подавляющем большинстве случаев функции захвата ресурсов могут вернуть отказ. На то они и ресурсы, чтобы исчерпываться.»

                                                                                                                                                                          и не делаете разницы между выделением ресурса и его захватом, то мне ничего не остаётся как указать на этот недочёт, уважаемый :)

                                                                                                                                                                          Теперь что касается RAII без исключений: RAII это всего лишь ООП-техника управления ресурсами. Вы отказались от «своих» слов, предложенных мною:

                                                                                                                                                                          «А по вашему вообще ООП без исключений невозможно получается?

                                                                                                                                                                          Этого я тоже не говорил.»

                                                                                                                                                                          Стало быть согласны ООП и исключения — не две стороны одной медали. И одно без другого вполне может существовать.
                                                                                                                                                                          Стало быть и RAII можно сделать без исключений.
                                                                                                                                                                          И ошибочки после конструктора проверить незазорно (я привёл пример работы с файловыми потоками).
                                                                                                                                                                          Или, например, какая может возникнуть ошибка в конструкторе какого-нибудь авто указателя, которому сдают на управление память? Что он не сможет в свою внутреннюю переменную-указатель положить переданное в параметре значение?

                                                                                                                                                                          Вы написали, что без исключений нельзя построить RAII.
                                                                                                                                                                          Для того, чтобы опровергнуть это утверждение — достаточно привести хотя бы один пример.
                                                                                                                                                                          Указанной парочки хватит?
                                                                                                                                                                            0
                                                                                                                                                                            и не делаете разницы между выделением ресурса и его захватом

                                                                                                                                                                            По сути дела, с точки зрения RAII, это одно и то же. В обоих случаях ресурс надо вернуть (очистить, освободить), и в обоих случаях может возникнуть отказ.
                                                                                                                                                                            то мне ничего не остаётся как указать на этот недочёт, уважаемый :)

                                                                                                                                                                            Вы так старательно заостряете внимание на мелочах — вам явно хочется увести обсуждение в сторону от исходной темы.
                                                                                                                                                                            Стало быть согласны ООП и исключения — не две стороны одной медали. И одно без другого вполне может существовать.
                                                                                                                                                                            Стало быть и RAII можно сделать без исключений.

                                                                                                                                                                            Из одного не следует другое. Я вам дважды предлагал привести пример реализации RAII без исключений для открытия файлов и обработки ошибок их открытия. В ответ — тишина. Если можно сделать — сделайте. Думаю, что на написание ваших сообщений с придирками к мелочам ушло больше вашего времени, чем на написание предлагаемого примера.
                                                                                                                                                                            И ошибочки после конструктора проверить незазорно (я привёл пример работы с файловыми потоками).

                                                                                                                                                                            «Проверяние ошибочек после конструктора» — это по сути не RAII, так как при использовании RAII ресурс выделен (захвачен), пока существует объект, им управляющий, и наоборот.

                                                                                                                                                                            Вы привели в пример весьма неудачное решение из стандартной библиотеки. Создается, к примеру, объект ofstream, но существование этого объекта не означает возможность записи в поток. Эта архитектура появилась до изобретения RAII в C++ (а возможно — и до введения в этот язык механизма исключений) и сохраняется лишь как наследство с целью совместимости.

                                                                                                                                                                            Для сравнения возьмите приведенный выше класс RaiiFile. Здесь у объекта имеется инвариант: пока он существует, файл открыт, как только удаляется — файл закрыт. С такой архитектурой работать значительно проще.
                                                                                                                                                                            Вы написали, что без исключений нельзя построить RAII. Для того, чтобы опровергнуть это утверждение — достаточно привести хотя бы один пример.Указанной парочки хватит?

                                                                                                                                                                            Ваши примеры мое утверждение не опровергают. Случай отсутствия возможности ошибок в конструкторе не охватывает все области применения RAII, поэтому он не может рассматриваться как общее решение задачи. Что же касается ofstream — аргументы приведены выше. Это неполноценное RAII, так как не соблюдается инвариант.
                                                                                                                                                                              0
                                                                                                                                                                              Ещё раз:
                                                                                                                                                                              Вы утверждаете, что RAII без исключений невозможно.
                                                                                                                                                                              Я привёл 2 опровергающих примера. С точки зрения формальной логики достаточно и одного.
                                                                                                                                                                              Вы акцентировали внимание на удобном Вам примере с файловыми потоками, не считая их по сути RAII. По вашему — RAII это однозначность: если объект есть — ресурс захвачен.
                                                                                                                                                                              По мне так более важная работа происходит в деструкторе. Он «автоматически», самостоятельно, незаметно для программиста подчищает ресурсы. Конструктор же работает «под управлением» программиста и так или иначе — всё-равно проверка его работы осуществляется. Или вызвать функцию или ловить исключение. Всё-равно писать код. Или сразу после создания объекта или «где-то внизу». Это уже не принципиально и не является сутью RAII.
                                                                                                                                                                              Суть его — в деструкторе.
                                                                                                                                                                              И в этом смысле файловые потоки stl — самое обычное RAII.

                                                                                                                                                                              А с какой «архитектурой» работать проще: с исключениями или с «ручной» проверкой ошибок — по большей части вопрос вкуса.
                                                                                                                                                                              У исключений есть, на мой взгляд, только 2 существенных плюса:
                                                                                                                                                                              1. Исключение не пропустишь. Вручную ошибку можно забыть проверить или, если какая-то стороняя библиотека, то в новой версии в ней могут появиться новые исключения.
                                                                                                                                                                              Но, опять таки, что лучше — упавшая на непойманном исключении программа или программа не проверившая ошибку и ковыляющая дальше — зависит от ситуации.

                                                                                                                                                                              2. Иерархия классов исключений, которая позволяет ловить их не по одиночке, а группами.
                                                                                                                                                                                0
                                                                                                                                                                                Я привёл 2 опровергающих примера. С точки зрения формальной логики достаточно и одного.

                                                                                                                                                                                Вы не привели ни одного опровергающего примера.

                                                                                                                                                                                Здесь ситуация такая же, как если бы я утверждал, что корни полинома 8й степени в общем случае нельзя найти аналитически, а вы «опровергали» бы это, приводя в пример уравнение вида x^8=64, которое таким образом решить можно.

                                                                                                                                                                                Наличие легких частных случаев не означает, что общая задача решается так же легко, как эти частные ее случаи.
                                                                                                                                                                                Вы акцентировали внимание на удобном Вам примере с файловыми потоками, не считая их по сути RAII.

                                                                                                                                                                                Удобный мне пример? Ни в коем случае. Это был удобный вам пример, который вы настойчиво проталкиваете к обсуждению. Я вынужден был его разобрать, раз вы так настаивали.
                                                                                                                                                                                По вашему — RAII это однозначность: если объект есть — ресурс захвачен.

                                                                                                                                                                                Ну а как иначе? Прочитайте, что ли, определение RAII. «Resource acquisition IS initialization». В случае с ofstream, объект после отработки конструктора инициализирован? Инициализирован. Ресурс захвачен? Не захвачен. Какое здесь может быть RAII?
                                                                                                                                                                                По мне так более важная работа происходит в деструкторе.

                                                                                                                                                                                Деструкторы — это необходимый механизм реализации RAII в C++. Но недостаточный. Другим необходимым механизмом являются исключения.
                                                                                                                                                                                Конструктор же работает «под управлением» программиста и так или иначе — всё-равно проверка его работы осуществляется. Или вызвать функцию или ловить исключение.

                                                                                                                                                                                Полагаю, под фразой «вызвать функцию» вы имели в виду «выполнить проверку»?

                                                                                                                                                                                Вот вы написали выше про деструктор: «Он «автоматически», самостоятельно, незаметно для программиста подчищает ресурсы».
                                                                                                                                                                                Это очень важное преимущество. За счет автоматизации подчистки ресурсов исключаются ситуации, когда программист «забыл» это сделать вручную. Также код очистки ресурсов не загромождает программу, облегчая понимание ее основной логики.

                                                                                                                                                                                Но не деструкторами едиными жив RAII. Есть еще вторая проблема — проверка ошибок при захвате ресурсов и досрочный выход из функции в случае ошибки. Этим в C++ занимается механизм исключений в конструкторах. Благодаря ему, вашими же словами: «автоматически», самостоятельно, незаметно для программиста проверяются ошибки при захвате ресурсов.

                                                                                                                                                                                Не находите сходство? В обоих случаях идет автоматизация одного из важных аспектов работы с ресурсами.

                                                                                                                                                                                Отсутствие исключений в конструкторах делает невозможной автоматизацию проверки ошибок при захвате ресурсов. От этого попытка реализации RAII в C++ теряет, грубо говоря, половину своих преимуществ.
                                                                                                                                                                                А с какой «архитектурой» работать проще: с исключениями или с «ручной» проверкой ошибок — по большей части вопрос вкуса.

                                                                                                                                                                                Если распространить вашу логику на деструкторы — то получится, что RAII можно сделать и без деструкторов, вручную очищая ресурсы, и это лишь вопрос вкуса.
                                                                                                                                                                                  0
                                                                                                                                                                                  Что-то у меня кнопки форматирования текста пропали, приходится отвечать просто текстом, без цитат.

                                                                                                                                                                                  1. У Вас прямым текстом было написано:
                                                                                                                                                                                  «RAII без исключений невозможно».
                                                                                                                                                                                  Никаких общих или не общих случаев. Просто написано: невозможно.

                                                                                                                                                                                  Я привёл примеры — ну хорошо, не нравятся Вам файловые потолки, но Вы уже второй раз игнорируете второй пример с автоуказателем.
                                                                                                                                                                                  У которого в конструкторе не может быть ошибок.

                                                                                                                                                                                  2. Ваши слова:
                                                                                                                                                                                  «В случае с ofstream, объект после отработки конструктора инициализирован? Инициализирован.»
                                                                                                                                                                                  С чего Вы взяли? Он — создан, а вот инициализирован он до конца (в его, объекта семантике) — это нужно у него узнать.
                                                                                                                                                                                  Да, спросить:
                                                                                                                                                                                  if (!myFileStream) return;
                                                                                                                                                                                  Или, как Вы настаиваете, ловить исключение:
                                                                                                                                                                                  try
                                                                                                                                                                                  {

                                                                                                                                                                                  }
                                                                                                                                                                                  catch (Exception& e)
                                                                                                                                                                                  {
                                                                                                                                                                                  return;
                                                                                                                                                                                  };

                                                                                                                                                                                  Оба варианта годятся.
                                                                                                                                                                                  Мне вариант с исключениями не нравится громоздкостью. Плюс Вы же сами упомянули, что исключения — «тяжелый» механизм.
                                                                                                                                                                                  Но не вижу причин делать тот или иной механизм обработки ошибок неотъемлемым признаком RAII.

                                                                                                                                                                                  3. «Вот вы написали выше про деструктор: «Он «автоматически», самостоятельно, незаметно для программиста подчищает ресурсы».
                                                                                                                                                                                  Это очень важное преимущество.»
                                                                                                                                                                                  Преимущество… Я настаиваю, что именно это и есть суть RAII. А не принцип проверки ошибок инициализации.

                                                                                                                                                                                  4.«Но не деструкторами едиными жив RAII. Есть еще вторая проблема — проверка ошибок при захвате ресурсов и досрочный выход из функции в случае ошибки. Этим в C++ занимается механизм исключений в конструкторах. Благодаря ему, вашими же словами: «автоматически», самостоятельно, незаметно для программиста проверяются ошибки при захвате ресурсов.»

                                                                                                                                                                                  Во-первых, Вы сами упоминали, что исключения — это не единственный способ сообщить об ошибке.
                                                                                                                                                                                  Во-вторых, никакой «автоматической проверки ошибок» исключениями — нет. Программист всё-равно должен написать код проверки.
                                                                                                                                                                                  Но по Вашему — не в месте возникновения ошибки, а в блоке catch. Ну, как я уже писал, это дело вкуса и к RAII не имеет отношения.
                                                                                                                                                                                  Единственное что однозначно характеризует RAII — это работа деструктора.
                                                                                                                                                                                  И именно поэтому не катит ваше утверждение:
                                                                                                                                                                                  «Если распространить вашу логику на деструкторы — то получится, что RAII можно сделать и без деструкторов, вручную очищая ресурсы, и это лишь вопрос вкуса.»
                                                                                                                                                                                    0
                                                                                                                                                                                    1. У Вас прямым текстом было написано:
                                                                                                                                                                                    «RAII без исключений невозможно».
                                                                                                                                                                                    Никаких общих или не общих случаев. Просто написано: невозможно.

                                                                                                                                                                                    Хорошо, уточню: RAII невозможно без исключений в общем случае. Если вы считаете это важным уточнением — то надеюсь, что этим ваше стремление к точности в мелочах удовлетворено?

                                                                                                                                                                                    Замечу также, что до того, как вы влезли в это обсуждение, обсуждалась задача обработки ошибок при захвате ресурсов и ее решение с помощью RAII. Из одного этого читателю, знакомому с RAII, должно было быть понятно, что частные случаи, когда ошибка при захвате ресурса возникнуть не может, не имеют никакого отношения к обсуждаемой изначально теме.

                                                                                                                                                                                    Вы уводите обсуждение в сторону, придираетесь к мелочам, игнорируете предложение реализовать обработку ошибок при захвате ресурсов с помощью RAII без исключений. Мне трудно представить, чтобы при этом вами двигало стремление к поиску истины.
                                                                                                                                                                                    Вы уже второй раз игнорируете второй пример с автоуказателем. У которого в конструкторе не может быть ошибок.

                                                                                                                                                                                    Что это меняет? Вернемся снова к аналогии с полиномами 8й степени. Вы можете привести бесконечное множество таких полиномов, корни которых можно найти аналитически. Но это не отменит тот факт, что в общем случае корни таких полиномов найти аналитически невозможно.

                                                                                                                                                                                    Вы можете приводить сколько угодно примеров таких ресурсов, при захвате которых не может возникнуть отказ. Но это не отменяет того, что существуют ресурсы, при захвате которых отказ возникнуть может.
                                                                                                                                                                                    С чего Вы взяли? Он — создан, а вот инициализирован он до конца (в его, объекта семантике) — это нужно у него узнать.

                                                                                                                                                                                    В языке C++ объект считается инициализированным после того, как завершил работу его конструктор. Разумеется, программист может обойти этот принцип, но концепция RAII подразумевает его строгое соблюдение.
                                                                                                                                                                                    Или, как Вы настаиваете, ловить исключение:… Мне вариант с исключениями не нравится громоздкостью.

                                                                                                                                                                                    Вы лукавите насчет громоздкости. Возможно, это свидетельствует об отсутствии у вас понимания эффективных способов использования исключений в C++. Прочитайте еще раз пример реализации RaiiFile с исключениями, который я привел выше, и укажите, где там находится громоздкий код.
                                                                                                                                                                                    Плюс Вы же сами упомянули, что исключения — «тяжелый» механизм.

                                                                                                                                                                                    Что поделаешь, это плата за удобство RAII. Не нравится «тяжесть» — вы всегда вольны отказаться от RAII.
                                                                                                                                                                                    Но не вижу причин делать тот или иной механизм обработки ошибок неотъемлемым признаком RAII.

                                                                                                                                                                                    В языке C++ это неотъемлемый признак RAII так же, как и деструкторы. Вы с тем же успехом могли бы доказывать, что деструкторы C++ не являются неотъемлемым признаком RAII.
                                                                                                                                                                                    Я настаиваю, что именно это и есть суть RAII. А не принцип проверки ошибок инициализации.

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

                                                                                                                                                                                    Укажите пожалуйста иной способ сообщить об ошибке в конструкторе в C++ так, чтобы компилятор понял, что это именно сообщение об ошибке, и предоставил соответствующую поддержку. Аналогично, деструктор — это не единственное место, где можно разместить код освобождения ресурсов. Что тогда — не считать освобождение ресурсов в деструкторе неотъемлемой частью RAII?
                                                                                                                                                                                    Во-вторых, никакой «автоматической проверки ошибок» исключениями — нет. Программист всё-равно должен написать код проверки.

                                                                                                                                                                                    А какое же тогда есть автоматическое, как вы сказали, освобождение ресурсов с помощью деструкторов? Программист все равно должен писать код освобождения (в деструкторе).
                                                                                                                                                                                    Но по Вашему — не в месте возникновения ошибки, а в блоке catch.

                                                                                                                                                                                    В блоке catch пишется не код проверки, а код обработки ошибок. И то не весь. Часть его пишется в деструкторах. Код проверки же пишется в конструкторе. Посмотрите еще раз приведенный выше пример с RaiiFile.
                                                                                                                                                                                    Ну, как я уже писал, это дело вкуса и к RAII не имеет отношения.

                                                                                                                                                                                    Я уже аргументировал сообщением выше, почему это ваше мнение ошибочно.
                                                                                                                                                                                    Единственное что однозначно характеризует RAII — это работа деструктора.

                                                                                                                                                                                    Вы указали только один из важных механизмов RAII, но упорно отрицаете второй. Полагаю, в этом ваше заблуждение. Без исключений на C++ невозможно полноценно реализовать парадигму RAII так же, как и без деструкторов.
                                                                                                                                                                                      0
                                                                                                                                                                                      «Как говорится, переубедить мне Вас не удастся, поэтому сразу перейду к оскорблениям»
                                                                                                                                                                                      :)

                                                                                                                                                                                      Мы досконально, как я вижу, выяснили позиции друг друга.
                                                                                                                                                                                      Каждый остался при своём мнении, которое однако не мешает никому из нас использовать принцип RAII по своему. Благо он это позволяет.
                                                                                                                                                                                        0
                                                                                                                                                                                        Ну хорошо, можно остановиться и на этом. «Agree to disagree», как говорят американцы.
                                                                                                                                                                      0
                                                                                                                                                                      Гораздо более пикантная ситуация — это ошибка в деструкторе.
                                                                                                                                                                        0
                                                                                                                                                                        Ошибка в деструкторе, да… Как ее обрабатывать — непонятно совершенно. Красивых решений на данный момент я не нашел. Разве что логировать. Прерывать исполнение деструктора, как правило, недопустимо даже при ошибках.
                                                                                                                                                  +3
                                                                                                                                                  разве так не проще?

                                                                                                                                                  int do_or_fail(void)
                                                                                                                                                  {
                                                                                                                                                  FILE *f1, *f2, *f3;
                                                                                                                                                  int retval = 0;
                                                                                                                                                  if(f1=fopen(«aaa.txt»,«r»)) {
                                                                                                                                                  if(f2=fopen(«bbb.txt»,«r»)) {
                                                                                                                                                  if(f3=fopen(«ccc.txt»,«r»)) {
                                                                                                                                                  /*… do something with the files… */
                                                                                                                                                  retval = 1;
                                                                                                                                                  fclose(f3);
                                                                                                                                                  }
                                                                                                                                                  fclose(f2);
                                                                                                                                                  }
                                                                                                                                                  fclose(f1);
                                                                                                                                                  }
                                                                                                                                                  return retval;
                                                                                                                                                  }

                                                                                                                                                  Что тут дублируется?
                                                                                                                                                    +2
                                                                                                                                                    Ничего не дублируется. Но если файлов открывать не три, а десять (или просто много), то нормальные отступы будут выглядеть гораздо хуже, чем в ситуации с goto.
                                                                                                                                                      +2
                                                                                                                                                      Меня код даже с тремя 3 файлами в одной функции смутил, а уж 10…
                                                                                                                                                        0
                                                                                                                                                        А каким образом вы будете писать код, если надо одновременно открыть 3 файла? В разных функциях будете открывать? А ошибки где проверять и закрывать уже открытые файлы, если часть из них открылось, а часть — нет?

                                                                                                                                                        Причем это не обязательно должны быть файлы, это могут быть любые другие ресурсы, у которых подобная модель захвата с возможностью отказа. Память, например.
                                                                                                                                                          0
                                                                                                                                                          Код можно структурировать и даже в принципе алгоритм реализовать — разными способами.
                                                                                                                                                          Но универсального ответа на ваш вопрос «как» — я дать не могу.
                                                                                                                                                          Это нужно разбираться в каждом конкретном проекте.
                                                                                                                                                          Ну и, повторю, наверное есть алгоритмы, где без goto или некуда или замена будет гораздо корявее, чем вариант с goto.
                                                                                                                                                          Но я с такими за 20 лет — не встречался.
                                                                                                                                                            0
                                                                                                                                                            Названия файлов в константу, дескрипторы в массив, если у вас сишников так все не просто, можно и флаги «файл 3 открыт» в массив записать. И никакого goto, и хоть 20 файлов открывай, кода больше не станет.
                                                                                                                                                            Я с таким за 3 года работы часто сталкивался, что в элементарных случаях пишут вот такую портянку, и говорят что «иначе не сделаешь», а в реальности надо было только немного подумать. Простите если кого-то сейчас обидел. Я всего лишь молодой и глупый питонист.
                                                                                                                                                      +5
                                                                                                                                                      В итоге какая глубина вложенности будет? И какой сдвиг форматирования вправо?
                                                                                                                                                        +1
                                                                                                                                                        vector<FILE*> files;
                                                                                                                                                        vector<string> names;
                                                                                                                                                        vector<bool> success;
                                                                                                                                                        // ресайз, заполнение имён файлов
                                                                                                                                                        ...
                                                                                                                                                        bool group_success = true;
                                                                                                                                                        for(int i = 0; i < N; i++){
                                                                                                                                                            success[i] = (file[i] = fopen(names[i].c_str(), "r")) == NULL;
                                                                                                                                                            if(!success[i]){
                                                                                                                                                                group_success = false;
                                                                                                                                                            }
                                                                                                                                                        }
                                                                                                                                                        if(group_success){
                                                                                                                                                            // any actions with files
                                                                                                                                                        }
                                                                                                                                                        for(int i = 0; i < N; i++){
                                                                                                                                                            if(success[i]){
                                                                                                                                                                fclose(files[i]);
                                                                                                                                                            }
                                                                                                                                                        }
                                                                                                                                                        
                                                                                                                                                          0
                                                                                                                                                          Только сейчас заметил, что там с NULL по "!=" сравнивать надо было. Опечатался.
                                                                                                                                                            +3
                                                                                                                                                            А что, если требуется захватывать разнородные ресурсы?
                                                                                                                                                              0
                                                                                                                                                              В enum перечислите типы ресурсов, по if или case применяйте открытие и закрытие, в массив вместо file* сделайте void*
                                                                                                                                                                0
                                                                                                                                                                Разнородные ресурсы — это значит, что они захватываются, в общем случае, разными функциями, имеющими разный интерфейс. Вызывать их в цикле по массиву указателей невозможно из-за различий в интерфейсе.

                                                                                                                                                                Можно и эту проблему решить, конечно. Создать, к примеру, функции-адаптеры. Для большого числа ресурсов это, наверно, хорошее решение. Но для среднего числа (3-10) — это стрельба из пушки по воробьям. Логика одной функции оказывается размазана на несколько функций, появляются циклы и дополнительные переменные. Для восприятия программы все это, на мой взгляд, тяжелее, чем конструкция с goto.
                                                                                                                                                                  0
                                                                                                                                                                  Подытоживая, для малого числа аргументов имеет смысл расписать каждый вручную, для большого — построить комбайн с унифицированным доступом к разным типам ресурсов.
                                                                                                                                                        +1
                                                                                                                                                        Такие конструкции прекрасно реализуются через
                                                                                                                                                        FILE *f1 = NULL, *f2 = NULL, *f3 = NULL;
                                                                                                                                                        int retval = 0;
                                                                                                                                                        do
                                                                                                                                                        {
                                                                                                                                                        if(!(f1=fopen(«aaa.txt»,«r»)))
                                                                                                                                                        break;
                                                                                                                                                        if(!(f2=fopen(«bbb.txt»,«r»)))
                                                                                                                                                        break;
                                                                                                                                                        if(!(f3=fopen(«ccc.txt»,«r»)))
                                                                                                                                                        break;
                                                                                                                                                        /*… do something with the files… */
                                                                                                                                                        retval = 1;
                                                                                                                                                        } while(FALSE);

                                                                                                                                                        if(!retval)
                                                                                                                                                        {
                                                                                                                                                        if (f1) fclose(f1);
                                                                                                                                                        if (f2) fclose(f2);
                                                                                                                                                        if (f3) fclose(f3);
                                                                                                                                                        }

                                                                                                                                                        Причем блок отката обычно выносится в отдельную функцию, которая позже вызывается как деструктор (например, если действия с файлами происходят не только в контексте вызова функции).
                                                                                                                                                          +4
                                                                                                                                                          Операторы return, break и continue — это по сути замаскированные goto, они нарушают структурность программы (по Дейкстре). Так что, если у вас в свое время воспитали устойчивое отвращение к goto — то забыли это сделать в отношении остальных вышеупомянутых команд.

                                                                                                                                                          Ну и приведенная вами программа имеет следующие недостатки: цикл-который-не-цикл, лишние проверки («if(f1) fclose(f1);»). Не всякий ресурс допускает такую простую проверку на предмет существования. Для тех ресурсов, которые нельзя так проверить, придется заводить отдельные логические переменные.

                                                                                                                                                          В общем, goto в данном случае красивее и эффективнее. И приведенный мной паттерн — это не мое изобретение (хотя я его в свое время независимо изобрел), а классический пример-исключение, показывающий, что есть случаи, где применение goto оправдано.
                                                                                                                                                            +1
                                                                                                                                                            При обучении озвучивался аргумент, что функции с goto выпадают из поля зрения оптимизатора. Потому и привился такой стиль программирования. Насколько я знаю, современные компиляторы не имеют такого недостатка. Кстати, приведенный мной пример не моя идея, это распространенный паттерн инициализации в драйверах Windows (функции создания объектов, StartDevice и прочие). Более адекватно код выглядит, если учесть, что описатели нужно закрывать не только здесь на откате при проблемах, но и при очистке объекта.
                                                                                                                                                            А в целом вы правы, это попытка не использовать goto там где он подходит лучше.
                                                                                                                                                              0
                                                                                                                                                              Спасибо, понятно.
                                                                                                                                                              Более адекватно код выглядит, если учесть, что описатели нужно закрывать не только здесь на откате при проблемах, но и при очистке объекта.

                                                                                                                                                              По-моему это неоптимальное решение. Если мы снова взглянем на RAII в C++ — то он выглядит примерно так:
                                                                                                                                                              class ResourceSet
                                                                                                                                                              {
                                                                                                                                                              private:
                                                                                                                                                                  Resource a;
                                                                                                                                                                  Resource b;
                                                                                                                                                                  Resource c;
                                                                                                                                                              public:
                                                                                                                                                                  ResourceSet(): a(), b(), c() {}    
                                                                                                                                                              }

                                                                                                                                                              При создании объекта типа ResourceSet его конструктор поочередно захватывает ресурсы a, b и c. Если какой-либо из этих ресурсов недоступен — то соответствующий конструктор бросает исключение, и тогда создание объекта ResourceSet прерывается преждевременно. Исключение летит дальше вверх. А поскольку объект ResourceSet не был создан до конца (он считается созданным до конца после того, как будут созданы все объекты-члены и завершено исполнение тела конструктора) — то его деструктор не вызывается. Вызываются только деструкторы тех членов, которые уже были созданы на момент генерации исключения.

                                                                                                                                                              Соответственно, при уничтожении объекта ResourceSet() деструкторы членов вызываются безусловно, так как гарантированно известно, что все члены класса были успешно созданы.

                                                                                                                                                              Чтобы реализовать это на C, нужно иметь функцию, реализующую конструктор. Эта функция будет завершаться либо успешно — и тогда известно, что все ресурсы, которые она должна была захватить, захвачены; либо неуспешно — и тогда известно, что никаких ресурсов не захвачено, и вызывать «деструктор» не нужно. В таком случае в функции, реализующей концепцию деструктора, можно не проверять каждый ресурс, был ли он на самом деле захвачен.
                                                                                                                                                              0
                                                                                                                                                              Эти операторы работают чётко в рамках конструкций: циклов, switch'ей и функций, и имеют вполне предсказуемые последствия.
                                                                                                                                                              В каком же состоянии окажутся ресурсы программы в результате goto — предсказать трудно.
                                                                                                                                                            0
                                                                                                                                                            del
                                                                                                                                                            0
                                                                                                                                                            Если я не ошибаюсь, существование тьюринг-полного P" языка (в котором отсутствует goto оператор), уже говорит о том, что всегда можно обойтись без goto.
                                                                                                                                                              +1
                                                                                                                                                              В самой машине Тьюринга нет ни goto, ни каких других операторов. Значит, без любых операторов можно обойтись. И что?
                                                                                                                                                                0
                                                                                                                                                                А еще нет goto в Brainfuck.
                                                                                                                                                                  –1
                                                                                                                                                                  Вы точно читали комментарий, на который я отвечал?
                                                                                                                                                                  Цитирую:
                                                                                                                                                                  Могу осторожно согласиться, что я просто не встречался с задачами, где без goto никак.

                                                                                                                                                                  А теперь вам вопрос, при чем тут другие операторы?