Поймать ошибку, вызванную конструктором в С++?

У меня есть класс foo (который я не могу изменить) только с одним конструктором, который принимает один аргумент, например:

foo bar("Hello!");

Поскольку конструктор может выдать ошибку, я хочу реализовать обработку ошибок. Моя первая попытка была такой:

try {
    foo bar("Hello!");
}
catch {
    cerr << "Something went horribly wrong...";
    return -1;
}

Однако теперь foo находится в рамках блока try и не может использоваться где-либо еще. Если я правильно понимаю, я не могу объявить объект без его инициализации, поэтому я могу объявить bar вне блока try. Итак, что мне делать, чтобы поймать ошибку, которую выдает конструктор?

EDIT: Чтобы уточнить, это в моем main, и в catch я прерву программу. Кроме того, аргумент — это файл, который будет открыт, поэтому нет известного безопасного ввода, который никогда не вызовет исключение.


person Anders    schedule 10.09.2015    source источник
comment
Поместите весь соответствующий код в блок try. Или в функции, которую вы вызываете в блоке try.   -  person juanchopanza    schedule 10.09.2015
comment
Под релевантным кодом вы имеете в виду код, который использует объект? Это означало бы большую часть моей программы. Кажется, что слишком много просто поймать ошибку, которая может возникнуть только во время инициализации?   -  person Anders    schedule 10.09.2015
comment
Хорошо, если большая часть вашей программы содержится в функции main(), верно? Так почему бы не поместить его в другую функцию, которую вы поместили в блок try?   -  person juanchopanza    schedule 10.09.2015
comment
Если вся ваша программа зависит от объекта bar и его не удалось сконструировать, у вас есть небольшая проблема.   -  person MSalters    schedule 10.09.2015
comment
@MSalters Да, знаю. Так что в этом случае я прерву программу. Извините за неясность по этому поводу.   -  person Anders    schedule 10.09.2015


Ответы (2)


Проблема довольно проста: конструктор дал сбой, поэтому объект bar так и не был создан. С++ обеспечивает это и не позволяет вам использовать bar в этом случае.

Вы можете решить это другим способом:

foo makeFoo()
{
   try {
     return foo("Hello!"); // May throw
   }
   catch(...) {
     return foo("Safe"); // We know that "Safe" will not throw.
   }
}

bar foo{makeFoo()};

Если вы хотите выйти из программы, если возникнет исключение, вы можете распечатать сообщение об ошибке и вызвать exit(EXIT_FAILURE) внутри улова.

person MSalters    schedule 10.09.2015
comment
Спасибо за ответ! Боюсь, не существует полностью безопасных входных данных, поскольку параметр представляет собой файл, который нужно прочитать. И я думаю, что в C++ нет null или чего-то подобного, что я мог бы вернуть? - person Anders; 10.09.2015
comment
@Anders: Объекты не могут быть null. Однако указатели могут быть nullptr. И есть boost::optional<foo>, который может содержать или не содержать foo. Если ваш основной файл отсутствует, вы, конечно, можете распечатать сообщение об ошибке и вызвать exit(EXIT_FAILURE) внутри улова. - person MSalters; 10.09.2015
comment
Не знал о exit. Это решает мою проблему. Спасибо! - person Anders; 10.09.2015

Вы можете использовать выделение кучи:

foo *p = 0;
try {
    p = new foo("parm");
} catch(const Error& err) {
    ...
}
foo& instance = *p;
// Here you can use instance normally...

delete p; // destroy before leaving scope (or use a smart pointer)
person 6502    schedule 10.09.2015
comment
Это дает вам разыменование нулевого указателя. Кроме того, почему бы не std::unique_ptr? - person MSalters; 10.09.2015
comment
@MSalters: Я предполагаю, что внутри тела catch он решит проблему, либо выделив рабочий объект, либо просто прервав программу и не выйдя за пределы области без рабочего объекта. С интеллектуальным указателем или с его использованием - это именно то, о чем я думал... - person 6502; 10.09.2015
comment
Это в моем main, а в catch я просто напечатаю сообщение об ошибке и return. - person Anders; 10.09.2015