Захват исключений из списка инициализаторов конструктора
Здесь любопытный. У меня есть класс A. Он имеет элемент класса B, который я хочу инициализировать в конструкторе A, используя список инициализаторов, например:
class A {
public:
A(const B& b): mB(b) { };
private:
B mB;
};
Есть ли способ уловить исключения, которые могут быть вызваны mB copy-constructor при использовании метода списка инициализаторов? Или мне нужно инициализировать mB в фигурных скобках конструктора, чтобы иметь try/catch?
Ответы
Ответ 1
Прочитайте http://weseetips.wordpress.com/tag/exception-from-constructor-initializer-list/)
Изменить: после большего количества копания они называются "Блоки try функции".
Я признаюсь, что не знал об этом, пока не посмотрел. Вы узнаете что-то каждый день! Я не знаю, является ли это обвинительным актом о том, как мало я использую С++ в наши дни, отсутствие знаний на С++ или часто византийские функции, которые засоряют язык. Хорошо, мне все равно нравится:)
Чтобы люди не могли перейти на другой сайт, синтаксисом функции try block for constructors оказывается:
C::C()
try : init1(), ..., initn()
{
// Constructor
}
catch(...)
{
// Handle exception
}
Ответ 2
Это не особенно красиво:
A::A(const B& b) try : mB(b)
{
// constructor stuff
}
catch (/* exception type */)
{
// handle the exception
}
Ответ 3
Я знаю, что прошло некоторое время с тех пор, как началось это обсуждение. Но эта конструкция try-and-catch, упомянутая Адамом, является частью стандарта С++ и поддерживается Microsoft VС++ и GNU С++.
Вот программа, которая работает. Кстати, catch автоматически генерирует другое исключение, чтобы сигнализировать о сбое конструктора.
#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;
}
Ответ 4
Вы могли бы работать с ленивой инициализацией, тем не менее, это держать unique_ptr для Reader в MyClass и создавать его с новым. Таким образом, вам даже не нужен флаг 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;
}
Конечно, есть также решения без каких-либо исключений, но я предположил, что это предпосылка в вашей настройке.
Ответ 5
Я не вижу, как вы это сделаете с синтаксисом списка инициализаторов, но я также немного скептически отношусь к тому, что вы сможете сделать что-нибудь полезное, поймав исключение в своем конструкторе. Очевидно, это зависит от дизайна классов, но в каком случае вы не сможете создать "mB" и по-прежнему иметь полезный объект "A"?
Вы также можете исключить пересылку исключения и обрабатывать его везде, где вызывается конструктор для A.