Разветвления C++ игнорирования исключения от конструктора

Я искал ТАК ответ на это, но не нашел то.

То, когда объект выдает исключение в конце конструктора, объект доступен или является этими из тех, 'зависит от технологии производства строительных работ'?

Пример:

    struct Fraction
    {
      int m_numerator;
      int m_denominator;
      Fraction (double value,
                int denominator);
    };
    Fraction::Fraction(double value, int denominator)
    :  m_numerator(0), m_denominator(denominator)
    {
      if (denominator == 0)
      {
/* E1 */        throw std::logic_error("Denominator is zero.");
      }
      m_numerator = static_cast<int>(value * static_cast<double>(denominator));
      double actual_value = 0.0;
      actual_value = static_cast<double>(m_numerator) / static_cast<double>(m_denominator);
      double error = fabs(actual_value - value);
      if (error > 5.0E-5)
      {
/* E2 */  throw std::logic_error("Can't represent value in exact fraction with given denominator");
      }
    }

Программа:

int main(void)
{
    try
    {
        Fraction f1(3.14159264, 4); // Throws exception, E2 above.
    }
    catch (...)
    {
        cerr << "Fraction f1 not exactly representable as fraction with denom. of 4.\n";
    }

    // At this point, can I still use f1, knowing that it is an approximate fraction?

    return EXIT_SUCCESS;
}

В этом примере может использоваться f1 после того, как исключение поймано, зная, что это - приближенное значение?

Элементы данных были созданы и инициализированы.

Я не вижу, что любой язык C++ постановляет, что это нарушено вышеупомянутым.

Править: Измененная ошибочная дельта оценивает от 5.0E05 до 5.0E-5.

5
задан Thomas Matthews 4 February 2010 в 00:19
поделиться

9 ответов

Ответ Джонатана верен. Кроме того, хотя дробь может находиться в действительном состоянии, я бы не рекомендовал использовать исключения для управления потоком и особенно для связи о состоянии объекта. Вместо этого подумайте о добавлении некой is_exactly_representable в API объекта Fraction, который возвращает bool.

4
ответ дан 18 December 2019 в 10:44
поделиться

throw in constructor = construction failed -> object unable

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

f = new Fraction(3.14159264, 4);

В этом случае f также нельзя использовать, потому что конструктор не завершил работу и указатель не был назначен. Деструктор не вызывается, и память освобождена , поэтому нет возможности использовать объект.

Следовательно, создавайте свой объект обычным образом, не используйте исключения, если вы собираетесь использовать класс. Используйте функцию-член is_exact (), чтобы определить, точна ли она после построения.

2
ответ дан 18 December 2019 в 10:44
поделиться

Когда объект выдает исключение в конце конструктора, действителен ли объект или это один из тех, которые «зависят от техники построения»?

Да, это действительно зависит . Я имею в виду, это зависит от того, что вы имеете в виду, объект действителен . Действительный может иметь ряд значений.

Известно, что объект, строительство которого было прервано, является частично построенным объектом. Теперь, если вы считаете частичное построение недопустимым состоянием, то да, такой объект будет недопустимым.

Уничтожение гарантируется, однако, в соответствии со схемой, указанной в C ++ / 15.2:

Объект, который частично построен или частично уничтожен , будет иметь деструкторы, выполненные для всех {{1} } полностью сконструированных подобъектов, то есть для подобъектов, для которых конструктор завершил выполнение , а деструктор еще не начал выполнение .

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

#include <iostream>
using namespace std;
struct A
{
    ~A() { cout<<"~A()\n"; }
};
struct B
{
    A a;
    B() { throw 1; }
    ~B() { cout<<"~B()\n"; } // never called
};
int main()
{
    try
    {
        B a;
    }
    catch (...)
    {
        cout << "caught\n";
    }
}
1
ответ дан 18 December 2019 в 10:44
поделиться

после JMD

Тогда в предложении catch доступно f1. Ответ тоже отрицательный. Итак, вы видите, что правила области видимости не позволяют вам даже задать этот вопрос в коде.

Единственное, что может выдать, что объект существует, - это запуск его деструктора - но он не запускается, если конструктор не завершил работу

1
ответ дан 18 December 2019 в 10:44
поделиться

Я согласен с fbrereto.

Если вы выдаете ошибку в конструкторе, которая эквивалентна заявлению «создание этого объекта не сработало» или «объект не может быть создан», и поэтому вам нужно обработать этот факт - я бы сделал только это для фатальных ошибок, для которых объект не может быть использован иначе, например, не удалось открыть файл, который мы ожидали открыть в классе MySettingsReader.

1
ответ дан 18 December 2019 в 10:44
поделиться

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

В любом случае, если вы используете RAII повсюду, все ресурсы будут правильно освобождены и не будет объекта для доступа. В случае ptr = new Foo (); переменная ptr сохраняет свое старое значение. Аналогично smartptr.reset (new Foo ()); вообще не будет вызывать функцию сброса.

Обратите внимание на ошибку использования оператора new в выражениях, которые создают другие объекты: somefunc (Foo (), new Bar ()); . Если конструктор Foo не работает, может произойти утечка памяти (в зависимости от порядка, в котором ваш компилятор обработал аргументы).

0
ответ дан 18 December 2019 в 10:44
поделиться

f1 выходит за рамки после обнаружения исключения. Его больше нет, поэтому вы не можете его использовать.

5
ответ дан 18 December 2019 в 10:44
поделиться

Нет, после того, как область действия f1 определена в exits, вы больше не сможете использовать объект. Итак, в вашем коде:

try
{
    Fraction f1(3.14159264, 4); // Throws exception, E2 above.

    // f1 can be used until here
}
catch (...)
{
}

// The scope that f1 was defined in is over, so the compiler will not let
// you reference f1

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

enum FractionOption { disallowInexact, allowInexact };

Fraction::Fraction(double value, int denominator,
                   FractionOption option = disallowInexact)
{
    ...
    if ((option == disallowInexact) && (error > 5.0E-5))
    {
        throw std::logic_error("Can't represent value ...");
    }
}

Fraction f1(3.14159264, 4, allowInexact);
2
ответ дан 18 December 2019 в 10:44
поделиться

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

Если бы f1 был указателем, который был выделен и построен внутри блока try, а конструктор (а не распределитель) выдал исключение, ваш указатель был бы на допустимую выделенную память. Содержит ли объект в этой памяти допустимые данные, будет зависеть от вашего конструктора; в основном, если данные были действительными до броска, они были бы действительными после броска.

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

0
ответ дан 18 December 2019 в 10:44
поделиться
Другие вопросы по тегам:

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