Подтвердить что ты не робот

Какой лучший метод для выхода из конструктора при условии ошибки в С++

Какая лучшая техника для выхода из конструктора при условии ошибки в С++? В частности, это ошибка, открывающая файл.

Спасибо за ответы. Я бросаю исключение. Здесь код (не знаю, если это лучший способ сделать это, но это просто)

// Test to see if file is now open; die otherwise 
if ( !file.is_open() ) {
    cerr << "Failed to open file: " << m_filename << endl;
    throw ("Failed to open file");
}   

Думаю, что мне нравится в С++, вам не нужно объявлять заброшенные исключения в объявлениях методов.

4b9b3361

Ответ 1

Лучшее предложение - это, вероятно, то, что говорит парашют. Но, пожалуйста, прочитайте мою осторожную заметку ниже.

См. FAQ по парашюту 17.2

[17.2] Как я могу обработать конструктор что не удается?

Выбросьте исключение.

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

Идея объекта "зомби" имеет много вниз. Вам нужно добавить запрос ( "инспектор" ) для проверьте этот бит "зомби", чтобы пользователи ваш класс может узнать, объект действительно жив, или если он зомби (т.е. объект "живой мертвый" ), и почти все места, где вы постройте один из ваших объектов (в том числе в рамках более крупного объекта или массив объектов), вам нужно проверить этот флаг состояния через оператор if. Вы также захотите добавить, если на ваш другие функции-члены: если объект зомби, делать не-op или, возможно, что-то более неприятное.

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


Слово предостережения с бросанием исключений в конструкторе:

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

class B
{
public:
    B()
    {

    }

    virtual ~B()
    {
        //called after D constructor exception is called
    }
};

class D : public B
{
public:
    D()
    {
        p = new char[1024];
        throw std::exception("test");
    }

    ~D()
    {
      delete[] p;
      //never called, so p causes a memory leak
    }

    char *p;
};

int main(int argc, char **argv)
{

    B *p;
    try
    {
        p = new D();
    }
    catch(...)
    {

    }


    return 0;
}

Защищенные/частные конструкторы с помощью метода CreateInstance:

Другой способ: сделать ваш конструктор закрытым или защищенным и создать метод CreateInstance, который может возвращать ошибки.

Ответ 2

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

Чтобы сделать конструктор, который не может завершиться неудачей, реорганизуйте код, который потенциально может сбой в методе init(), и пусть конструктор сделает как можно меньше работы, а затем потребует, чтобы все пользователи класса вызывали init() сразу после строительства. Если init() не удается, вы можете вернуть код ошибки. Обязательно запишите это в своей документации по классу!

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

Ответ 3

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

Ответ 4

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

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

Ответ 5

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

Ответ 7

Есть только 1 хороший способ выйти из конструктора, который находится в ошибке, то есть для создания исключения.

Неужели это ошибка? вы пытаетесь добавить слишком много к конструктору?

Часто люди будут пытаться вставить какое-то начальное взаимодействие в конструктор, например добавить имя файла в конструктор файла. Ожидаете ли вы, что он сразу откроет этот файл или вы просто установите какое-то состояние, отличается ли оно от file.open(filename), нормально ли он не работает?

Ответ 8

Лучше всего сделать бросок исключения. То, для чего они предназначены, и любая попытка дублировать поведение, которое вы получаете, скорее всего, не сработает.

Если вы не можете использовать исключение, по какой-то причине используйте nothrow. Пример в стандарте, пункт 18.4.1.1 9:

t* p2 = new(nothrow) T;    // returns 0 if it fails

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

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

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

Действительно, исключения - лучший способ пойти.