Кресты / Говнокод #13087 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
#ifndef SAFE_RELEASE
#define SAFE_RELEASE(x) \
   if(x != NULL)        \
   {                    \
      x->Release();     \
      x = NULL;         \
   }
#endif

#define SAFE_DELETE(a) if( (a) != NULL ) delete (a); (a) = NULL;

#ifndef SAFE_ARRAY_DELETE
#define SAFE_ARRAY_DELETE(x) \
   if(x != NULL)             \
   {                         \
      delete[] x;            \
      x = NULL;              \
   }
#endif

#define SAFE_FREE( p )      if( p ) { free( p ) ; p=NULL ; }

Я вот все никак не могу забыть старый код из доков макрософт по COM, а также из книги Андре Ла Мота.

Два макроса до сих пор висят среди доков на сайте мс (по коду догадаетесь какие):

http://msdn.microsoft.com/ru-RU/library/windows/desktop/dd743946(v=vs.85).aspx

Запостил: LispGovno LispGovno, (Updated )

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

    • Мне сейчас 100% заминусуют, но эта куйня ничем не лучше макроса.
      Ответить
      • > ничем не лучше макроса
        Лучше. Она хотя бы не так забагована, как макросы, перечисленные выше 😉
        Ответить
        • Имелась ввиду ссылка на указатель, я думаю.

          template <typename T> void SafeRelease(T *&pT) {
              if (pT) {
                  pT->Release();
                  pT = NULL;
              }
          }
          Ответить
          • А в COM такая форма передачи выходных параметров используется для совместимости с Си, так что это правильно. Хотя не вижу никакого удовольствия писать под COM на си.
            Ответить
          • Если уж писать на крестах - то лучше сделать нормальный смартпоинтер. А от ссылки никакого толку нет - код перестанет быть совместимым с си, а удобства не прибавится.
            Ответить
            • Причем примитивный смартпоинтер наваять - дело пяти минут:
              template <class T> class GovnoPtr {
              public:
                  GovnoPtr() : ptr(0) {}
                  GovnoPtr(T * p) : ptr(p) {
                      if (ptr)
                          ptr->AddRef();
                  }
                  GovnoPtr(const GovnoPtr &other) : ptr(other.ptr) {
                      if (ptr)
                          ptr->AddRef();
                   }
                  ~GovnoPtr() {
                      if (ptr)
                          ptr->Release();
                  }
                  T * operator = (T *p) {
                      if (p)
                          p->AddRef();
                      if (ptr)
                          ptr->Release();
                      ptr = p;
                      return p;
                  }
                  T * operator -> () { return ptr; }
                  T & operator * () { return *ptr; }
                  operator bool () { return ptr != 0; }
              private:
                  T * ptr;
              };
              Ответить
              • P.S. По идее в конструкторе от T * не нужен AddRef() т.к. у свежесозданного объекта уже единичка на счетчике.
                Ответить
                • >По идее в конструкторе от T * не нужен AddRef()
                  да, также как и в T * operator = (T *p) {
                  Ответить
                  • Да, я тупанул. Этот оператор должен был принимать ссылку на GovnoPtr. Тогда AddRef нужен. А здесь - не нужен.
                    Ответить
              • explicit добавь в GovnoPtr(T * p)
                поддержки const корректности не хватает
                T * operator = (T *p) { не безопасен с точки зрения исключений и не хваает такого же оператора, только копирования
                Ответить
                • > explicit
                  > поддержки const корректности
                  Логично

                  > не безопасен с точки зрения исключений
                  Зачем AddRef и Release будут кидать исключения? Они ведь даже не крестоблядские...
                  Ответить
                  • P.S. COM'овский метод, имхо, вообще не может кидать крестоблядские исключения, т.к. это нарушит интероперабельность с другими языками.
                    Ответить
                    • DLL поидеи тоже не может кидать исключения, но на деле что для DLL, что COM разрешают кидать исключения, когда пишут в рамках этих технологий, но на одном компиляторе и настройках в одном проекте. Не спрашивай зачем, возможно для модульности. Вообщем лучше от таких питушков уберечься, так как это почти ничего не стоит.
                      Ответить
                      • > DLL поидеи тоже не может кидать исключения
                        Моя DLL, че хочу то и делаю. Соглашения о вызовах и исключениях не зафиксированы, поэтому я всегда могу написать свои и следовать им.

                        А вот COM это не та вещь, в которой допустимы вольности. Не нравятся правила COM'а - мути свою аналогичную технологию, но не создавай людям батхерты, называя это COM'ом.

                        К тому же "Exceptions aren't allowed to flow across a COM interface boundary. Because there is no binary contract for C++ exceptions, COM cannot marshal them from one thread to another.". Т.е. с COM объектом из соседнего процесса так уже не поработаешь.

                        P.S. Исключение в Release равносильно исключению в деструкторе.
                        Ответить
                        • Поддерживаю по всем пунктам, но лучше написать тк, чтобы не было потом мучительно больно за ...
                          Ответить
              • А что это вообще за AddRef() и Release()? Что-то из винапи?
                Ответить
                • COM же. Методы интерфейса IUnknown, от которого порождены все остальные интерфейсы.

                  AddRef увеличивает счетчик использований на 1.
                  Release уменьшает, и удаляет объект, если счетчик достиг нуля.
                  QueryInterface позволяет получить другой интерфейс по его GUID'у.
                  Ответить
  • Как нормальный образованный человек может написать такое идиотское говно?
    if (nothingElseToDo) SAFE_FREE(resources);
    else doSomething();
    Почему говнокодеры так любят макросы и одновременно с этим ну никак не могут в них?
    Ответить
    • потому что те, кто могут в макросы - понимют что они не нужны
      Ответить
      • > понимют что они не нужны в большинстве ситуаций (но не всегда)
        fxd
        Ответить
      • Он не нашел, он привел пример, на котором этот макрос поведет себя неадекватно - else уйдет внутрь макроса, а не к тому ифу, к которому должно относиться.

        Основы макроёбства - не жалеть скобок в выражениях и do { ... } while (0) в стейтментах, чтобы потом об этом не жалеть 😉
        Ответить
        • А почему {...} просто не достаточно вокруг макроса?
          Ответить
          • if ... else опять же ломается
            #define RELEASE(x) { if (x) x->Release(); }
            if (itIsTime) RELEASE(resources); // semicolon at the end finishes `if` statement
            else doSmth();
            Ответить
          • Макрос завернутый в do { ... } while (0) ведет себя неотличимо от функции в том плане, что требует ставить после него ";". А с голым блоком { ... } получается наоборот, что не всегда приятно.

            Сравни
            if (a)
                SAFE_FREE(x)
            else
                SAFE_FREE(y)
            и
            if (a)
                SAFE_FREE(x);
            else
                SAFE_FREE(y);
            Второе, естественно, смотрится привычней и интуитивней.
            Ответить
              • > Лучше так
                Нет, не лучше. Этот вариант забагуется на примере Романа, равно как и просто { ... }. Конструкцию с if(0){}else{...} юзают не в таком случае, а когда макросом пытаются эмулировать какой-нибудь foreach или особый if.

                Емнип других способов замутить макрос, ведущий себя как вызов void функции кроме do { ... } while(0) и нет.
                Ответить
                • > макросом пытаются эмулировать какой-нибудь foreach или особый if.
                  Пример использования if(0){}else для foreach и\или if ? if(0){}else - если это не работает, то зачем так делают?
                  Ответить
                  • > если это не работает, то зачем так делают
                    Оно работает, но семантика получается как у любой другой управляющей конструкции - if/for/while и т.п. Вот для эмуляции новых подобных конструкций оно юзабельно. Для эмуляции void функций - нет.

                    > Пример использования if(0){}else для foreach
                    В Qt'шной реализации foreach'а for завернут в if(0){}else чтобы переменные, описанные в for'е не вылезали наружу из-за ебанутого скопинга в msvc6. Если интересно, а искать исходники кютихи влом - могу выложить сюда этот кусочек.
                    Ответить
                    • >Если интересно, а искать исходники кютихи влом - могу выложить сюда этот кусочек.
                      Не, спасибо. Я видел. Тот щё гонокод. Хуже только BOOST_FOREACH
                      Ответить
            • Естественнее смотрится Паскаль, в котором перед else точка с запятой никогда не ставится, потому что точка с запятой будет означать конец всего оператора if.

              А вообще же тот, кто уже обжёгся, ставит фигурные скобки при каждом удобном случае, даже вокруг единственного оператора:
              if (a) {
                  SAFE_FREE(x);
              } else {
                  SAFE_FREE(y);
              }
              Разве так не надёжнее?
              Ответить
              • Я всегда ставлю скобки. Но весьма многие не ставят их там, где они не обязательны.
                Ответить
                • > Я всегда ставлю скобки.
                  А я ставлю их в нетривиальных случаях - более одного уровня вложенности. Примерно так:
                  // здесь без скобок
                  if (x)
                      x->release();
                  
                  // если одна из веток сложна - скобки пишу в обе стороны
                  if (x) {
                      x->show();
                  } else {
                      y->show();
                      z->show();
                  }
                  
                  // два и более уровней вложенности - тоже скобки
                  for (int i=0; i<10; i++) {
                      for (int j=0; j<10; j++) {
                          printf("%d %d\n", i, j);
                          printf("%d %d\n", i, j);
                      }
                  }
                  
                  // но
                  for (int i=0; i<10; i++)
                      for (int j=0; j<10; j++)
                          a[i][j] = 5;
                  Ответить
                  • Ненене, я скобки ставлю вообще всегда. Мне когда-то в код влезли:

                    if (someVar != nil)
                         // log("куча текста");
                    
                    release(someVar);


                    А я потом понять не мог, почему у меня память течь начала, да и ещё в промышленных масштабах, по 3 мб на одну отрисовку
                    Ответить
              • > Разве так не надёжнее?
                Скобки то само-собой надежнее. Но согласитесь: лучше написать макрос (а лучше вообще не писать их лишний раз без причины 😉 так, чтобы он адекватно работал во всех контекстах, чем объяснять в документации как именно нужно его юзать, и надеяться, что ее будут читать...

                > А вообще же тот, кто уже обжёгся, ставит фигурные скобки при каждом удобном случае
                Обжегшись на молоке дуют на воду... Проблема то в том, что макрос через жопу написан. А пофиксить пытаются последствия.
                Ответить
  • Из всех макросов полезен только SAFE_RELEASE. От остальных польза разве что в запихивании NULL'а. Но в любом случае для с++ они как-то не особо идиоматичны.

    P.S. Кстати макросы написаны неправильно, нужно больше do { ... } while(0).
    Ответить
    • Коллеги, работавшие в мотороле, рассказывают слезливые истории про их нестандартные функции освобождения памяти, вызывающие ребут телефона при передаче им NULL. Десткая психика не выдержала травмы, никак не могу отучить их писать эти проверки.
      Ответить
      • > вызывающие ребут телефона при передаче им NULL
        Ужоснах какой-то. В чем смысл такой функции? Оптимизация путем устранения лишней проверки? Так один хер все в страхе будут проверять, и проверка вернется, правда вместо одного места она будет размазана по всему коду ровным слоем...
        Ответить
        • я не знаю, но победосный зохват моторолы рынка мобильных аппаратов как-бы намекает нам
          Ответить

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

Я, guest, находясь в здравом уме и твердой памяти, торжественно заявляю:

    А не использовать ли нам bbcode?


    8