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

Захват исключений из списка инициализаторов конструктора

Здесь любопытный. У меня есть класс A. Он имеет элемент класса B, который я хочу инициализировать в конструкторе A, используя список инициализаторов, например:

class A {
    public:
    A(const B& b): mB(b) { };

    private:
    B mB;
};

Есть ли способ уловить исключения, которые могут быть вызваны mB copy-constructor при использовании метода списка инициализаторов? Или мне нужно инициализировать mB в фигурных скобках конструктора, чтобы иметь try/catch?

4b9b3361

Ответ 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.