Перехват исключений из списка инициализатора конструктора - PullRequest
46 голосов
/ 02 октября 2008

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

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

    private:
    B mB;
};

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

Ответы [ 5 ]

81 голосов
/ 02 октября 2008

Прочитайте http://weseetips.wordpress.com/tag/exception-from-constructor-initializer-list/)

Редактировать: после дополнительных копаний они называются «Функциональными пробными блоками».

Признаюсь, я тоже этого не знал, пока не пошел искать. Вы чему-то учитесь каждый день! Я не знаю, является ли это обвинением в том, как мало я сегодня использую C ++, в моем недостатке знаний C ++ или в часто византийских функциях, которые засоряют язык. Ах, хорошо - мне все еще нравится:)

Чтобы людям не приходилось переходить на другой сайт, синтаксис функционального блока try для конструкторов выглядит так:

C::C()
try : init1(), ..., initn()
{
  // Constructor
}
catch(...)
{
  // Handle exception
}
17 голосов
/ 02 октября 2008

Это не особенно красиво:

A::A(const B& b) try : mB(b) 
{ 
    // constructor stuff
}
catch (/* exception type */) 
{
    // handle the exception
}
4 голосов
/ 13 июля 2011

Я знаю, что прошло некоторое время с тех пор, как началось это обсуждение. Но упомянутая Адамом конструкция try-and-catch является частью стандарта 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;
}
1 голос
/ 08 февраля 2016

Вы можете работать с ленивой инициализацией, то есть удерживать 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;
}

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

0 голосов
/ 02 октября 2008

Я не понимаю, как бы вы сделали это с помощью синтаксиса списка инициализаторов, но я также немного скептически отношусь к тому, что вы сможете сделать что-нибудь полезное, перехватив исключение в своем конструкторе. Очевидно, это зависит от дизайна классов, но в каком случае вы не сможете создать «mB», и у вас останется полезный объект «A»?

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...