Каково различие между броском и броском с аргументом перехваченной исключительной ситуации?

@Ber: Я добавил проверку к модели, подобной этому

class Parent(models.Model):
  name = models.CharField(max_length=255)
  favoritechild = models.ForeignKey("Child", blank=True, null=True)
  def save(self, force_insert=False, force_update=False):
    if self.favoritechild is not None and self.favoritechild.myparent.id != self.id:
      raise Exception("You must select one of your own children as your favorite")
    super(Parent, self).save(force_insert, force_update)

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

21
задан WilliamKF 26 September 2009 в 16:45
поделиться

2 ответа

В зависимости от того, как вы организовали иерархию исключений, повторное генерирование исключения путем присвоения имени переменной исключения в операторе throw может срезать исходный объект исключения.

Выражение throw без аргументов вызовет текущий объект исключения с сохранением его динамического типа, тогда как выражение throw с аргументом вызовет новое исключение, основанное на типе static аргумента для throw ].

Например,

int main()
{
    try
    {
        try
        {
            throw Derived();
        }
        catch (Base& b)
        {
            std::cout << "Caught a reference to base\n";
            b.print(std::cout);
            throw b;
        }
    }
    catch (Base& b)
    {
        std::cout << "Caught a reference to base\n";
        b.print(std::cout);
    }

    return 0;
}

Как написано выше, программа выведет:

Caught a reference to base
Derived
Caught a reference to base
Base

Если throw b заменить на throw , то внешний catch также поймает первоначально созданное исключение Derived .Это все еще сохраняется, если внутренний класс перехватывает исключение Base по значению, а не по ссылке - хотя, естественно, это будет означать, что исходный объект исключения не может быть изменен, поэтому любые изменения в b будут не должно отражаться в исключительной ситуации Derived , перехваченной внешним блоком.

28
ответ дан 29 November 2019 в 20:25
поделиться

Во втором случае согласно C ++ Standard 15.1 / 6 конструктор копирования не используется:

Выражение throw без операнда повторно генерирует обрабатываемое исключение. Исключение повторно активируется с существующим временным; новый объект временного исключения не создается. Исключение больше не считается обнаруженным; следовательно, значение uncaught_exception () снова будет истинным.

В первом случае будет сгенерировано новое исключение в соответствии с 15.1 / 3:

Выражение выброса инициализирует временный объект, называемый объектом исключения, тип из которых определяется путем удаления любых cv-квалификаторов верхнего уровня из статического типа операнда throw и настройки тип от «массив T» или «функция, возвращающая T» до «указатель на T» или «указатель на функцию, возвращающую T», соответственно. <...> Временное значение используется для инициализации переменной, указанной в соответствующем обработчике (15.3). Тип выражения throw не должен быть неполный тип или указатель или ссылка на неполный тип, отличный от void *, const void *, volatile void * или const volatile void *. За исключением этих ограничений и ограничений на сопоставление типов, упомянутое в 15.3, операнд throw обрабатывается точно как аргумент функции при вызове (5.2.2) или операнд оператора возврата.

В обоих случаях конструктор копирования требуется на этапе выброса (15.1 / 5):

Когда брошенный объект является объектом класса, а конструктор копирования используется для инициализировать временную копию невозможно, программа имеет неправильный формат (даже если временный объект иначе можно было бы удалить). Точно так же, если деструктор для этого объекта недоступен, программа имеет неправильный формат (даже если временный объект может быть удален в противном случае).

16
ответ дан 29 November 2019 в 20:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: