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

    +170

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    7. 7
    8. 8
    transaction::~transaction()
      {
        if (db_) {
          int rc = db_->execute(fcommit_ ? "COMMIT" : "ROLLBACK");
          if (rc != SQLITE_OK)
            throw database_error(*db_);
        }
      }

    (c) http://code.google.com/p/sqlite3pp/source/browse/trunk/sqlite3pp.cpp#486

    пожалуй, здесь нехватает картинки в стиле Nichtlustig с подписью "лемминг делает throw в деструкторе"

    Запостил: iddqd, 27 Марта 2011

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

    • На ~statement() такое же.
      Ответить
    • Это печально, что нельзя бросать исключения в деструкторе. Часто было бы полезным.

      Кстати, вроде бы в C++0x деструкторы сделали nothrow. Чтобы не искушать.
      Ответить
      • Ну тут надо заметить, что никакого "нельзя бросать исключения в деструкторе" нет и никогда не было. Что "нельзя", так это давать исключению вылетать из деструктора наружу. Это действительно нехорошо. А вот бросать исключения в деструкторе можно сколько вашей душеньке угодно - до тех пор, пока эти исключения ловятся и "проглатываются" не вылетая за пределы этого деструктора.

        В данном случае проблема именно в этом. Т.е. проблема тут не в наличии 'throw', а в отсутствии локального 'catch'.
        Ответить
        • >проблема тут не в наличии 'throw', а в отсутствии локального 'catch'.
          Я думаю, это подразумевалось. Просто не было так развернуто, как у Вас.
          С другой стороны, особого смысла делать локальные throw/catch как-то неожиданно - проще выйти по условию.
          Ответить
          • у меня откуда-то внутренее убеждение, что такие операции, как создание\уничтожение обьектов, не должно выполняться относительно долго, т.е. с использованием таких "тяжелых" конструкций, как исключения (внутренние)
            По поводу (не-)возможности бросания исключений из деструктора, все верно - если команда на уничтожение поступила - обьект должен быть удален безусловно, особенно при наличии во многих языках сборщика мусора - который вряд ли решит корректно, что делать, если обьект не мог быть удален.
            Еще одна причина, почему это бессмысленно - если ресурс с обьектом недоступен - значит, он тоже не существует (хотя бы в данный момент), следовательно, "связь" с обьектом нарушена, следовательно - и обьект тоже превратился в мусор.
            А задача по уборке мусора (что-то вроде "дефрагментации") должна выполняться сторонним процессом.

            Что и требовалось доказать
            Ответить
            • Всё же жаль, что нельзя хоть как-то прореагировать на неудачу операции освобождения ресурса, если делать это в деструкторе, как предполагается по RAII. Приходится заводить явный close() и вызывать его вручную, а потом ещё проверять в деструкторе и вызывать, если нужно. И специальную обёртку, которая бы вызывала в своём деструкторе close() и тут же обрабатывала неудачу.
              Ответить
              • это да. Хотя, в деструкторе предполагается, что мы умеем избавляться от ресурса в любом случае, "насильственно", т.е. если ресурс мы не можем удалить - мы просто о нем забываем (пусть потом сторонний процесс или поток прибирается). А освобождение "по-хорошему" - это как раз явный close(), вызываемый вручную.
                Ответить
        • Спасибо, кадет Биглер.
          Ответить

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