Вот любопытный. У меня есть класс A. У него есть элемент класса B, который я хочу инициализировать в конструкторе A, используя список инициализаторов, например:
class A {
public:
A(const B& b): mB(b) { };
private:
B mB;
};
Есть ли способ перехватывать исключения, которые могут быть сгенерированы копирующим конструктором mB при использовании метода списка инициализаторов? Или мне придется инициализировать mB в скобках конструктора, чтобы попытаться / уловить?





Я не понимаю, как вы это сделаете с синтаксисом списка инициализаторов, но я также немного скептически отношусь к тому, что вы сможете сделать что-нибудь полезное, перехватив исключение в своем конструкторе. Очевидно, это зависит от дизайна классов, но в каком случае вы не сможете создать «mB», но все еще будете иметь полезный объект «A»?
Вы также можете позволить исключению просачиваться и обрабатывать его везде, где вызывается конструктор для A.
Прочтите http://weseetips.wordpress.com/tag/exception-from-constructor-initializer-list/)
Обновлено: после дополнительных копаний они называются «Функциональные пробные блоки».
Признаюсь, я этого тоже не знал, пока не пошел искать. Ты узнаешь что-то каждый день! Я не знаю, является ли это обвинением в том, что я мало использую C++ в наши дни, в моем незнании C++ или в часто византийских особенностях, засоряющих язык. Ну да ладно - мне до сих пор нравится :)
Чтобы людям не приходилось переходить на другой сайт, синтаксис функционального блока try для конструкторов выглядит следующим образом:
C::C()
try : init1(), ..., initn()
{
// Constructor
}
catch(...)
{
// Handle exception
}
Фу. Я не удивлен, что есть какой-то способ сделать это, но это отличный пример того, почему я ненавижу синтаксис инициализатора C++ ...
ПРИМЕЧАНИЕ: вы не можете обработать исключение при использовании функциональных блоков try в конструкторах. даже если ваш блок catch (...) не генерируется повторно, исключение все равно ускользает от вызывающей стороны.
В статьях Херба Саттера «Гуру недели» также есть хорошее обсуждение функциональных блоков: gotw.ca/gotw/066.htm
@Aaron Это правда, но все же стоит упомянуть, что вы можете повторно генерировать другое исключение, которое в любом случае полезно. Скажем, генерируется какое-то общее исключение, но вы скорее выбрасываете свой собственный тип, который вызывающий объект уже может обработать.
Это не особо красиво:
A::A(const B& b) try : mB(b)
{
// constructor stuff
}
catch (/* exception type */)
{
// handle the exception
}
Я знаю, что прошло некоторое время с тех пор, как началась эта дискуссия. Но эта конструкция «попробуй и поймай», упомянутая Адамом, является частью стандарта C++ и поддерживается Microsoft VC++ и GNU C++. Вот программа, которая работает. Кстати, уловка автоматически генерирует еще одно исключение, чтобы сигнализировать о сбое конструктора.
#include <iostream>
#include <exception>
#include <string>
using namespace std;
class my_exception: public exception
{
string message;
public:
my_exception(const char* message1)
{
message = message1;
}
virtual const char* what() const throw()
{
cout << message << endl;
return message.c_str();
}
virtual ~my_exception() throw() {};
};
class E
{
public:
E(const char* message) { throw my_exception(message);}
};
class A
{
E p;
public:
A()
try :p("E failure")
{
cout << "A constructor" << endl;
}
catch (const exception& ex)
{
cout << "Inside A. Constructor failure: " << ex.what() << endl;
}
};
int main()
{
try
{
A z;
}
catch (const exception& ex)
{
cout << "In main. Constructor failure: " << ex.what() << endl;
}
return 0;
}
Однако вы можете работать с отложенной инициализацией, то есть удерживать unique_ptr для Reader в MyClass и создавать его с помощью new. Таким образом, вам даже не нужен флаг has_reader, но вы можете просто увидеть, является ли ваш unique_ptr начальным или нет.
#include <iostream>
#include <memory>
using namespace std;
class MyOtherClass
{
public:
MyOtherClass()
{
throw std::runtime_error("not working");
}
};
class MyClass
{
public:
typedef std::unique_ptr<MyOtherClass> MyOtherClassPtr;
MyClass()
{
try
{
other = std::make_unique<MyOtherClass>();
}
catch(...)
{
cout << "initialization failed." << endl;
}
cout << "other is initialized: " << (other ? "yes" : "no");
}
private:
std::unique_ptr<MyOtherClass> other;
};
int main()
{
MyClass c;
return 0;
}
Конечно, есть и решения, вообще не использующие исключений, но я предполагал, что это обязательное условие в ваших настройках.
Возможно, это должен был быть комментарий. В любом случае, есть еще несколько полезных вещей, которые вы можете сделать там, например, диагностировать проблему, зарегистрировать ее и выдать более информативное исключение, чем то, которое вы поймали. Вы правы в том, что ничего не можете сделать с А или его членами.