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

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

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

    private:
    B mB;
};

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
57
0
24 653
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

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

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

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

patatahooligan 21.08.2019 11:53
Ответ принят как подходящий

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

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

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

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

C::C()
try : init1(), ..., initn()
{
  // Constructor
}
catch(...)
{
  // Handle exception
}

Фу. Я не удивлен, что есть какой-то способ сделать это, но это отличный пример того, почему я ненавижу синтаксис инициализатора C++ ...

Mark Bessey 02.10.2008 03:07

ПРИМЕЧАНИЕ: вы не можете обработать исключение при использовании функциональных блоков try в конструкторах. даже если ваш блок catch (...) не генерируется повторно, исключение все равно ускользает от вызывающей стороны.

Aaron 02.10.2008 03:37

В статьях Херба Саттера «Гуру недели» также есть хорошее обсуждение функциональных блоков: gotw.ca/gotw/066.htm

Void 24.09.2009 00:12

@Aaron Это правда, но все же стоит упомянуть, что вы можете повторно генерировать другое исключение, которое в любом случае полезно. Скажем, генерируется какое-то общее исключение, но вы скорее выбрасываете свой собственный тип, который вызывающий объект уже может обработать.

Petr 25.04.2019 13:57

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

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;
}

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

Другие вопросы по теме