На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: ANDLL, ALXR
Страницы: (12) [1] 2 3 ...  11 12 все  ( Перейти к последнему сообщению )  
> #define ИЛИ template? , C++
   
#define ИЛИ template
Гости не могут просматривать результаты голосования.
Гости не могут голосовать 
    Решил немного оживить раздел голосований. Тематические вопросы. Начнём с одного из популярных


    ExpandedWrap disabled
      #define MACROMAX(x,y) \
          ((x < y)?y:x)

    ExpandedWrap disabled
      template <typename T1, typename T2>
      T1 templatemax(T1 x, T2 y)
      {
          return (x < y)?y:x;
      }
    Сообщение отредактировано: B.V. -
      #defnie или const, теоретически вопрос мог бы и так стоять, кстати...
      Сообщение отредактировано: Руслан -
        #define - зло. Если задача решается без него, то всегда предпочту альтернативное решение.

        Добавлено
        А вообще странная голосовалка и варианты. Нажал "Результаты" :)
          #define, как и другие макроопределения - юзается для кроссплатформенного программирования + для гардов компиляции(ну не считая include, без которого никуда, пожалуй единственный полезный макрос, который юзается везде и всегда), ну может быть еще какую вещь упустил. Во всех остальных случаях - за такое нужно бить по рукам, и больно бить.

          А то потом люди бедные приходят и задают вопросы, аля - а что я делаю не так, что у меня какой нибудь std::min/std::max не компилируется при включенном windows.h.
          Или еще есть любители из макроса целую функцию сделать. Потом такую функцию - продебажить нереально, а порой очень нужно, пусть даже она и работает корректно, и приходится ее переписывать кодом.
          Вообще макросы - это тупой мусор, захламляющий код. Я лучше отдам предпочтение юзанью goto, чем использовать макросы в качестве каких нибудь функций. Их использовать нужно тогда и там, где без них либо очень затруднительно что либо сделать, либо совсем нереально.
          Например кроссплатформенное программирование.

          Добавлено
          Вот в том же MFC - иди продебаж карту сообщений. Я дебажил - и это было больно. А нужно было очень, по другому не понятно было где косяк.
          Вот из за тех же макросов эту MFC и гнобят все. Да вообще у майкрософта подход к программированию какой то нубско-студенческий. Всюду юзают goto и где не попадя макросы, даже вместо констант. Порой смотришь их MSDN или код какой нибудь функции и диву даешься - неужели там действительно тупарей берут, которые без макросов и goto писать не могут ниче.
          Сообщение отредактировано: KILLER -
            А где у них в примерах goto?
              Цитата OpenGL @
              А где у них в примерах goto?

              Везде. Начиная от примеров в MSDN и заканчивая API функциями и классами. Странно что ты задаешь такой вопрос. Наверное в MSDN давно не заглядывал или в их код например в том же MFC ?

              Добавлено
              Например, можешь зайти в C:\Program Files\Microsoft SDKs\Windows\v7.0\Samples, если у тебя SDK стоит, и грепануть по goto(ну или вообще открой любые на свое усмотрения их сырцы и глянь что там).

              Добавлено
              Ну или еще можно в сырцах MFC/ATL грепануть по goto -> C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc

              Ну MSDN, на вскидку вот буквально недавно работал с SecurityDescriptor'ами, там вообще кишит этими goto в примерах, например https://msdn.microsoft.com/ru-ru/library/wi...5(v=vs.85).aspx

              Добавлено
              C #define вместо констант - у меня сложилось такое впечатление, что там это правило, а не исключение из правил.

              Вообще эталон говнокода: https://msdn.microsoft.com/en-us/library/wi...9(v=vs.85).aspx

              Добавлено
              У меня порой складывается впечатление, что в MSDN примеры пишут какие нибудь индусы, которым платят за количество строчек кода.
              Сообщение отредактировано: KILLER -
                Цитата KILLER @
                У меня порой складывается впечатление, что в MSDN примеры пишут какие нибудь индусы, которым платят за количество строчек кода.

                дефайны использовались в C, и многим было привычно использовать именно их. Думаю, что это исторически так сложилось и дальше поддкрживается из соображений совместимости.
                Тоже самое с goto - Win API не кидают исключения, они возвращают код ошибки. Так было привычно работать в те времена (да блин, даже сейчас коллеги все еще боятся использовать исключения! и стараются вернуть код ошибки хотя пишут уже исключительно на C#). Собственно говоря, именно для обработки ошибок MS и используют goto. Менять поведение нельзя из-за обратной совместимости.
                Ну и кроме того, подсчитай, сколько всего #define'ов определено в хидерах MFC, а также всех WinAPI... если заменить каждый дефайн на const int, то это <количество дефайнов> * 4 байта в пустую используемой памяти. И если сейчас всем глубоко наплевать на это, то в 1985 (именно тогда появился Windows 1.0)... ну ладно, даже в 1995-ом году, когда Винда стала самостоятельной операционной системой, к расходу памяти относились очень осторожно. Ну а дальше уже нельзя было менять дефайны на константы ради обратной совместимости. Более того, ради того, чтобы код был в едином стиле приходится и дальше следовать утвержденным когда-то давно правилам.

                Так что причины, почему MFC и WinAPI написаны именно так очевидны.
                  Цитата Fester @
                  если заменить каждый дефайн на const int, то это <количество дефайнов> * 4 байта в пустую используемой памяти.

                  Константы не используют память. Точнее, память под них будет выделена только если ты начнёшь брать указатели на эти константы и что-то с ними делать, а в 99.9% случаев это нафиг не надо.
                    Цитата Fester @
                    дефайны использовались в C

                    И что у них была какая то другая цель, отличная от С++? Они что в C были макросами, что в С++ стали макросами. В С есть константы, на сколько я помню, так что такое оправдание не катит.

                    Цитата Fester @
                    Думаю, что это исторически так сложилось и дальше поддкрживается из соображений совместимости.

                    Как сложилось? Не было типов данных, констант и переменных? Писали все в макросах? Или что?

                    Цитата Fester @
                    Тоже самое с goto - Win API не кидают исключения, они возвращают код ошибки. Так было привычно работать в те времена (да блин, даже сейчас коллеги все еще боятся использовать исключения! и стараются вернуть код ошибки хотя пишут уже исключительно на C#). Собственно говоря, именно для обработки ошибок MS и используют goto.

                    Ты знаешь, я сколько писал на чистом С, как то не приходилось использовать goto. С goto хоть С, хоть в С++, хоть в C# - везде хреново, и без него великолепно все возвращается и очищается. Просто кто то ленится и пишет goto где не попадя.

                    Цитата Fester @
                    Менять поведение нельзя из-за обратной совместимости.

                    Из за какой совместимости то? Не совсем тебя понял.

                    Цитата Fester @
                    Ну и кроме того, подсчитай, сколько всего #define'ов определено в хидерах MFC, а также всех WinAPI... если заменить каждый дефайн на const int, то это <количество дефайнов> * 4 байта в пустую используемой памяти. И если сейчас всем глубоко наплевать на это, то в 1985 (именно тогда появился Windows 1.0)... ну ладно, даже в 1995-ом году, когда Винда стала самостоятельной операционной системой, к расходу памяти относились очень осторожно. Ну а дальше уже нельзя было менять дефайны на константы ради обратной совместимости. Более того, ради того, чтобы код был в едином стиле приходится и дальше следовать утвержденным когда-то давно правилам.

                    Так а причем тут дефайны в хидерах, где например они объявляют битовые маски ? Речь про дефайны зашла в примерах конкретно, и в тех местах - где они ломают стандартные функции. У них часть дефайнов конкретно в библиотеках - написаны как раз в тему. А часть - не в тему. Хорошо - пусть они там экономили на константах, но объясни мне, зачем функции/методы/и целые классы оборачивать в дефайны? Тоже для экономии места или как?

                    Цитата Fester @
                    Ну а дальше уже нельзя было менять дефайны на константы ради обратной совместимости. Более того, ради того, чтобы код был в едином стиле приходится и дальше следовать утвержденным когда-то давно правилам.

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

                    Цитата Fester @
                    Так что причины, почему MFC и WinAPI написаны именно так очевидны.

                    Мне нисколько не очевидны.

                    Добавлено
                    Цитата OpenGL @
                    Константы не используют память. Точнее, память под них будет выделена только если ты начнёшь брать указатели на эти константы и что-то с ними делать, а в 99.9% случаев это нафиг не надо.

                    Тогда темболее, объяснение Fester про память было не совсем в тему.

                    Добавлено
                    Цитата Fester @
                    да блин, даже сейчас коллеги все еще боятся использовать исключения! и стараются вернуть код ошибки хотя пишут уже исключительно на C#

                    А чего бояться? Боятся что исключение их укусит? Или они просто матерые сишники, которые по привычке в придачу пишут все в одном классе, не используют наследование, и все методы у них статические, и то! Только из за того, что в C# нельзя написать функцию вне класса? Может им на пенсию пора? :D
                      Цитата OpenGL @
                      Константы не используют память.

                      Это всегда так было или только в некоторых компиляторах? Я так понимаю, что это оптимизация компилятора... или как?


                      Цитата KILLER @
                      И что у них была какая то другая цель, отличная от С++? Они что в C были макросами, что в С++ стали макросами. В С есть константы, на сколько я помню, так что такое оправдание не катит.

                      Я не могу расписать тебе в чем именно в те лохматые годы отличались константы от дефайнов. Но я все таки исхожу из того, что программисты были не глупее тебя и точно знали что и почему они делали. По каким-то причинам были выбраны именно макросы. Если ты хочешь доказать, что программисты в MS в середине 80-х были дебилы - доказывай.


                      Цитата KILLER @
                      Ты знаешь, я сколько писал на чистом С, как то не приходилось использовать goto. С goto хоть С, хоть в С++, хоть в C# - везде хреново, и без него великолепно все возвращается и очищается.

                      Конечно. Все можно обойти ифами. C этим никто не спорит. В некоторых случаях goto заметно упрощает код. Собственно говоря, ты используешь finally в своем коде? А ведь по сути это тот же goto ;) Избегать goto исключительно ради избегания - это не самая хорошая тактика. И если использование goto упрощает понимаение кода, то я лично не вижу ничего плохого в его использовании.

                      Цитата KILLER @
                      Из за какой совместимости то? Не совсем тебя понял.

                      Обратной. Чтобы ты мог в старом коде использовать новые библиотеки.
                      Грубо говоря, если у тебя есть функция
                      ExpandedWrap disabled
                        int Div (int a, int b)
                        {
                          if (a < b)
                            return NOT_POSSIBLE;
                          if (b == 0)
                            return DIVISIO_BY_ZERO;
                          return a / b;
                        }


                      то если ты перепишешь так:
                      ExpandedWrap disabled
                        int Div (int a, int b)
                        {
                          if (a < b)
                            throw "a must be >= b";
                          if (b == 0)
                            throw "division by zero";
                         
                          return a / b;
                        }


                      то тебе придется переписать уже существующий код.

                      Добавлено
                      Цитата KILLER @
                      А чего бояться? Боятся что исключение их укусит?

                      Боятся, что исключение не будет обработано и это приведет к крэшу :)
                      У нас один такой бояка везде вставляет
                      ExpandedWrap disabled
                        ...
                        catch (...)
                        {
                          Log.Error ("any exception");
                        }

                      после такого очень забавно вылавливать баги :)
                        Цитата Fester @
                        Это всегда так было или только в некоторых компиляторах? Я так понимаю, что это оптимизация компилятора... или как?
                        Не всегда. Не оптимизация, новое требование Стандарта... запамятовал, какой именно версии. И что там на предмет C, без понятия, и в стандарты лезть лень. Не исключено, что по-прежнему const int и К° являются lvalue даже со static, и нии... в смысле, пофигу.
                        Обработка ошибок посредством __leave в примерах MSDN появилась только с появлением этого самого __leave в компиляторе. Обработка ошибок посредством SEH в примерах MSDN сильно усложняет перенос кода на другие языки. Говнокод в лице примеров в MSDN является просто крайне разжёванной реализацией иллюстрируемой идеи, опять-таки для пользователей других языков. Только тут ещё и другой нюанс: эти примеры учат, и как учебные примеры они и должны быть разжёваны

                        Добавлено
                        И вообще. Вы совсем не те #define обсуждаете.
                          Цитата Fester @
                          Если ты хочешь доказать, что программисты в MS в середине 80-х были дебилы - доказывай.

                          А что доказывать? В 80-х думаю что не то что бы MSDN'а, Даже тех функций которые сейчас там описаны не было, ну может за исключением каких то объектов ядра или еще чего то.

                          Цитата Fester @
                          Собственно говоря, ты используешь finally в своем коде?

                          Нет. Я на С/С++ в основном программирую. А если следовать твоей логике - любой return/break/continue/и т.п. по сути тот же goto. Только return - не нарушает структуры выполнения программы, а goto нарушает. Именно по этому его всегда и гнобили.

                          Цитата Fester @
                          Избегать goto исключительно ради избегания - это не самая хорошая тактика. И если использование goto упрощает понимаение кода, то я лично не вижу ничего плохого в его использовании.

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

                          Цитата Fester @
                          Обратной. Чтобы ты мог в старом коде использовать новые библиотеки.

                          Обратная совместимость нарушается тогда, когда ты меняешь например сигнатуру метода/функции/класса и т.д.
                          Например была у тебя функция bool OpenFile(file_name, desired_acces, dos_format);
                          Потом вышла новая версия венды, и последний параметр стал вообще нафиг никому не нужен, так вот если его уберут - то сломают обратную совместимость, и по этому делают либо вторую функцию, либо оставляют прежнюю, но делают оговорку в документации - что третий параметр зарезервирован и должен быть равен NULL(например).

                          А когда ты рефакторишь что то внутри функции, не меняя ее сигнатуру - как ты можешь поломать обратную совместимость? Ты может не goto имел ввиду или перепутал что то с чем то?

                          Цитата Fester @
                          то тебе придется переписать уже существующий код.

                          В данном случае не обязательно. По крайней мере до возникновения ошибки ничего не случится. И ты немного съехал с темы. Речь шла про goto, а не про коды возврата/исключения. Если я внутри функции избавлюсь от goto - ничего я не поломаю. Так что это пока не аргумент.

                          Цитата Fester @
                          Боятся, что исключение не будет обработано и это приведет к крэшу :)

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

                          Цитата Fester @
                          У нас один такой бояка везде вставляет

                          С кодами возврата можно отгребсти куда больше проблем. И таких ошибок, что catch(...) тебе сказкой покажется. Там хоть бряк можно поставить, и сразу туда вылететь в этот catch.
                          Так что это слабенький аргумент.
                            Цитата KILLER @
                            Обратная совместимость нарушается тогда, когда ты меняешь например сигнатуру метода/функции/класса и т.д.

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


                            Цитата KILLER @
                            По моему это хуже крэша.

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

                            Цитата KILLER @
                            Коды возврата тебе тут не помогут. Если ты боишься что где то не обработаешь исключение, то почему ты не боишься того, что где то ты не проверишь возвращаемое значение?

                            потому что исключение может прилететь откуда угодно, а все возвращаемые значения заранее известны.
                              Цитата Fester @
                              Обратная совместимость нарушается, когда меняется поведение класса.

                              Я же тебе написал - что ты немного не в ту сторону съехал. Причем тут поведение классов меняется? Мы не обсуждали return/throw. Ты написал:
                              Цитата Fester @
                              Собственно говоря, именно для обработки ошибок MS и используют goto. Менять поведение нельзя из-за обратной совместимости.

                              Цитата Fester @
                              Ну а дальше уже нельзя было менять дефайны на константы ради обратной совместимости.


                              В данном случае обратная совместимость не ломается. Потому что, если ты избавляешься от goto(не меняешь поведение, поведение можно и с goto поменять), а именно стоит задача избавиться от goto.
                              Ну и с дефайнами и константами не совсем понял, как там ломается обратная совместимость?

                              Цитата Fester @
                              Обратная совместимость также может поменяться если ты просто переименуешь или добавишь еще одно одно исключение.

                              Зачем ты это пишешь? Ведь это не имеет никакого отношения к обсуждаемой теме. Еще обратная совместимость ломается когда ты меняешь типы данных, меняешь логику, меняешь сигнатуру, и т.д. Но как это относится к макросам и goto, я в упор не понимаю? Это попытка уйти от прямого вопроса? Я у тебя спросил - как ты поломаешь обратную совместимость, просто избавившись от goto, ты приводишь мне пример с return/throw и приводишь мне какие то случаи когда она еще может ломаться. Да я и так знаю когда она ломается, а когда нет. А вот ты похоже не до конца понимаешь. Иначе ответил бы на мой вопрос, а не лил воду про то, что я у тебя не спрашивал.

                              Цитата Fester @
                              ДА мало ли примеров, когда можно нарушить обратную совместимость не изменяя сигнатуру?

                              https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%...%81%D1%82%D1%8C
                              Цитата
                              Обра́тная совмести́мость — наличие в новой версии компьютерной программы или компьютерного оборудования интерфейса, присутствующего в старой версии, в результате чего другие программы (или человек) могут продолжать работать с новой версией без значительной переделки (или переучивания). Полная обратная совместимость означает, что при замене старой версии компонента на новую, функционирование всей системы в целом не нарушится.


                              Цитата Fester @
                              Другой момент, что изменив сигнатуру ты спровоцируешь ошибки и другой разработчик сразу узнает, что что-то поменялось.

                              Именно эти ошибки и есть - сломанная обратная совместимость. Если ты избавился от goto внутри функции - ничего ты не сломаешь.

                              Цитата Fester @
                              Крэш - это полный отказ, в то время как какая-то незавершенная или неправильная операция совсем не означает, что приложение больше неработоспособно.

                              А зачем нужно приложение, которое работает не верно? Вообще то по хорошему - лучше упасть, чем работать неверно. Лучше уж прямой крешь, чем неверная работа приложения, которая может привести к невесть чему, включая искажение или полную потерю информации или еще чего.

                              Цитата Fester @
                              Например наш софт сбирает данные и пишет их в БД. Плохо конечно, если какие-то данные не запишутся, но не смертельно, а если прога крэшнится, то не запишится вообще ничего и никто не знает, когда это заметят.
                              Поэтому крэш - это очень плохо.

                              Вообще то лучше пусть они вообще не сохранятся, чем сохранятся неверные данные. Если ты 8 часов сидел забивал данные в базу без комита, а потом к концу 8-ого часа у тебя все упало, то ты сам виноват. Тебе никто не запрещал сохранять данные. А вот если ты пишешь одно, а созхраняет в базу совершенно другое - то это в 100 раз хуже. ИМХО.

                              Цитата Fester @
                              Поэтому крэш - это очень плохо.

                              Это плохо, но не смертельно. А вот когда у тебя программа работает с некорректными данными, а ты еще об этом даже не догадываешься - вот тут будет полнейшая жопа. Ты просто можешь реально влететь в такую жопу. Что потом забудешь return, и будешь вместо него везде писать throw.

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

                              Блин, я не понимаю как вы программируете? Ты юзаешь функцию и незнаешь - кидает она тебе исключение или нет? или что? Да откуда бы оно не прилетело - ты можешь открыть дамп и посмотреть стек, и сразу понять - что и в каком месте у тебя вылетело. А в вашем C#, так вообще не нужно никуда лезть и смотреть, дефолтный обработчик, даже если ты там ниче не ловил и так тебе покажет какую никакую информацию в окошке и в журнале событий.
                              А вот когда твое приложение дебет с кредетом не сведет, и бедный предприниматель уволит всех своих сотрудников, вот тогда ты точно поймешь - как ты ошибался.
                                Цитата KILLER @
                                ... а именно стоит задача избавиться от goto.
                                Зачем? Во-первых, это известный legacy C паттерн, пол-POSIX-а так писано, к слову. Во-вторых, это тот же finally, только руками.
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (12) [1] 2 3 ...  11 12 все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0595 ]   [ 18 queries used ]   [ Generated: 28.03.24, 14:09 GMT ]