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

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
void Exf2dMW::closeEvent(QCloseEvent* event)
{
  int win_num = _winManager->numberOfModellingWindows();
  // if more than one modelling windows, just destroy current one:
  if (win_num > 1) {
    event->accept();
    delete this;
  }
  // if only one window and handle closing model properly, then destroy it:
  else {
    if( handleCloseModel() ) {
      event->accept();
      delete this;
      delete _winManager;
    }
    else
      event->ignore();
  }
}

Еще кусочек говнокода коллеги, я не думал что так можно писать..

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

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

    • если операторы работы с кучей и сама куча правильно реализована, то она не будет удалять не свои аллоки:
      unsigned char buf[] = { 0x01, 0x02, 0x03, 0x04 };
      delete buf; printf("0x%08X - 0x%08X\n", buf, *((unsigned int*)buf));

      delete this бывало встречал в коммерческих проектах... по большому счету криминальное здесь только delete локальной переменной... хотя в принципе тоже должно работать, если this был не последним выделенным аллоком на странице, и если между delete this и delete локальной переменной не встрянет другой поток, который перетрет ее значение...
      Ответить
    • и не только на стэке, дело в том что он closeEvent - это event handler. то есть скорее всего объект будет юзаться еще и после удаления.
      Ответить
      • Если event->accept() отписывает его или уничтожает источник события (закрывает окно), то не будет.
        Ответить
  • Можно. Без видения полной картины утверждать наверняка нельзя, но скорее всего это не ошибка и не говнокод. Может быть даже где-то в другом месте документирована такая стратегия.

    Можно предположить, что есть менеджер окон, есть несколько окон, на каждое навешен обработчик события закрытия, размещённый в динамической памяти. Если окон несколько -- event->accept() закрывает сответствующее окно, обработчик больше ни с чем не связан и не нужен, удаляется. Если осталось последнее окно, handleCloseModel() запрашивает у пользователя подтверждение и либо закрывает это окно и удаляет уже не нужный менеджер, либо игнорирует событие. Всё нормально.
    Ответить
    • ну мы видели полную картину и оно крашилось 🙂 closeEvent() - это стандартный евент-хэндлер в Qt, и в документации уж точно не предусмотрено удалять объект во время обработки события. Для этого в Qt есть функции типа deleteLater(). Ну а менеджер окон тоже относится к клиентскому коду. Вы описали правильное поведение, но оно не должно достигаться удалением объекта самим себя. Для этого нужно посылать сигнал менеджеру окон и он сам удалит последнее окно, а затем и себя.
      Ответить
      • Ага, closeEvent() -- это переопределённый метод виджета, а не стороннего обработчика. Проверьте, установлен ли флаг Qt::WA_DeleteOnClose, если установлен, то delete удаляет уже удалённый объект, если нет, то вроде ничего плохого произойти не должно.
        Ответить
  • стоит ли подобное использовать - каждому свое
    но структуру системы проще понять и поддерживать, если сущности создаются и удаляются там, где они используются, а не так что создадим здесь, тут что-то там вызовем (явно не деструктор) и, опа, оно уже удалено:(
    Ответить
  • а ещё "delete this;" приводит к проблемам при множественно наследовании:
    class A { TypeA fieldA; ... };
    class B { public: TypeB fieldB; void DeleteB() { delete this; } ... };
    class C : A, public B { ... };
    ...
    C *c = new C();
    C->DeleteB();

    всё равно что сделать так:
    void Fn_DeleteB(B *b) { delete b; }
    Fn_DeleteB(new C());

    метод DeleteB() получит в качестве this не указатель на (*c), а указатель на с->fieldB, т.е. не на начало области освобождаемой памяти.

    Даже если наследоваться никто не будет, не думаю что так стоит писать (
    Ответить
    • "мы не будем драться с тобой, Мэп. Мы просто тебя забудем" (ц)

      не думаю, что корректно удалять себя, т.к. получится, что мы находимся внутри несуществующего объекта
      Ответить
      • Если не обращаться к нестатическим членам объекта, то проблем нет.
        Ответить
      • И это в лучшем случае 🙂 В моём примере ещё и память будет разбита
        Ответить
      • Бестселлер «Эскхатологические методы в программировании».
        А вообще, интересная проблема о нахождении внутри несуществующего объекта — на самом стыке программирования и философии!
        Ответить
    • То, что вы тут написали не имеет никакого отношения ни к `delete this`, ни к множественному наследованию.

      В языке С++ выполнять полиморфное удаление объекта (т.е удаление через указатель на базовый подобъект) разрешается только в том случае, если этот базовый подобъект имеет виртуальный деструктор. Вы в своем коде нарушили это правило, поэтому Ваш код порождает неопределенное поведение (а уж какой там указатель прийдет в `delete` - на `fieldB` или еще куда - это бесполезное гадание на кофейной гуще).

      Ваш код ничем принципиально не оличается от обычного

      struct B {};
      struct D : B {};
      ...
      B *b = new D;
      delete b; // <- ОБЛОМИСЬ: неопределенное поведение


      и, еще раз, ни к `delete this`, ни к множественному наследованию никакого прямого отношения не имеет.

      Добавьте в класс `B` виртуальный деструктор, чтобы соблюсти требования языка С++, и сразу все станет работать нормально, даже с множественным наследованием 🙂
      Ответить
  • `delete this` - я ни какой конкретной инфы не видел почему так делать нельзя/что так делать можно. при условии что к объекту больше обращений не происходит, проблем возникать не должно. не забываем про мнимый `this->` перед обращением к методам и членам класа. и я видел места где этим народ пользуется.

    с другой стороны, я лицезрел подобную фишку в одной системе - удаление объекта получателя сообщения внутри обработчика этого же сообщения. не так откровенно, но тем неменее. и я видел как это весьма спектакулярно и произвольно валило приложение весьма разнообразными способами: фреймворк пытался что-то там еще с этим объектом делать в эпилоге кода диспатча сообщений. имеет смысл на мэйл листах вашего фреймворка поспрашивать.
    Ответить
  • `delete this` - устоявшаяся широко распространенная идиома. Ничего нелегального с точи зрения языка в ней нет. И никакой говнокодовости в ней нет. Надо просто уметь ею пользоваться и думать, что делаешь. Злоупотреблять, разумеется, ею не стоит, как и всем остальным в С++.

    Аргументы типа "объект может быть на стеке" - бред сивой кобылы. Если я, автор объекта, сказал, что объект не может быть "на стеке", значит от там быть не может. А если кто-то умудрится его там создать - вот тот пусть потом и расхлебывает возникшие проблемы. (Добро пожаловать в С++!)

    Разумеется, если объекты предназначены исключительно для динамческого создания, то не составит труда исключить их статическое создание или локальное создание. Способов достичь этого много. (Static constructor idiom - лишь один пример).

    Постить вырванный из контекста код с `delete this` и утверждать что из-за этого он является говнокодом - дилетантство самого низкого пошиба.

    Потенциал для говнокодовости в этом примере, конечно, есть. В частности, имете место обращение к некоему `_winManager` после `delete this`. Если `_winManager` - поле уже удаленного объекта , то мы действительно имеем дело с говнокодом. Но из примера не видно, откуда берется этот `_winManager`, поэтому судить невозможно.
    Ответить
    • `delete this` - устоявшаяся широко распространенная идиома.

      Я бы не сказал что устоявшаяся и широко распространенная. Как тут уже подметили, создание и удаление объекта должно быть подконтрольно одной сущности, а так как очевидно, что объект не может создать себя сам, неправы тут Вы. И не надо кидаться выражениями, типа "дилетанство самого низкого пошиба" или "бред сивой кобылы".
      Ответить
      • Если объект создаётся фабричным статическим методом create, а удаляется методом destroy — то создание и удаление таки подконтрольно одной сущности.

        Это действительно устоявшаяся широко распространенная идиома. Но применимая в редких конкретных ситуациях, в комплексе с другими средствами.
        Ответить
        • Надо почитать про это, но в любом случае, метод называется destroy - я не сильно понимаю необходимость этого метода, так как использование виртуального деструктора и оператора delete дает тот же самый эффект.
          Ответить
          • Да, перегрузка операторов new и delete, конструктор и деструктор позволяют решить большинство задач. Но иногда нужно уничтожать объект небезусловно, и тогда приходится использовать другой интерфейс.

            Например, объект с внутренним счётчиком ссылок. Метод grab увеличивает счётчик на 1, метод ungrab — уменьшает, и, если он достиг 0, удаляет объект. Это эффективнее smart_ptr.

            Или же create при некоторых условиях берёт уже созданный объект из готового статического пула, а destroy, если объект был из пула, возвращает его туда, не разрушая.
            Ответить
            • Спасибо!

              P.S. в любом случае к подопытному коду это не относится 🙂
              Ответить
  • нда, облажался я ^_^ Не знаю почему вдруг пришло в голову всё это, но как пришло, так и ляпнул не подумав. Наговнокодил, блин.
    Ответить
    • Сайт, сборник статей (и не только). Автор пишет "о языках программирования". Статьи больше "поржать", хотя есть интересные моменты... Вот уж не знаю, что автор курит для снятия стресса...
      http://okante.narod.ru/D/
      >Большинству современных языков программирования не хватет морально-этической и чувственной составляющей...
      Ответить
      • Где Вы такое находите...
        "Здравствуйте, меня зовут Николай Валуев. Немного о себе. Сейчас я профессиональный боксёр. Также у меня есть рот. И ещё я туда ем."
        Может пригласить автора на ГК?
        Ответить

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

Где здесь C++, guest?!

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


    8