Как симулировать внутреннее исключение в C ++ - PullRequest
5 голосов
/ 14 мая 2010

В основном я хочу имитировать .NET Exception.InnerException в C ++. Я хочу поймать исключение из нижнего слоя, обернуть его другим исключением и снова выбросить в верхний слой. Проблема в том, что я не знаю, как обернуть пойманное исключение в другое исключение.

struct base_exception : public std::exception
{
    std::exception& InnerException;

    base_exception() : InnerException(???) { } // <---- what to initialize with
    base_exception(std::exception& innerException) : InnerException(innerException) { }
};

struct func1_exception : public base_exception 
{
    const char* what() const throw()
    {
        return "func1 exception";
    }
};

struct func2_exception : public base_exception
{
    const char* what() const throw()
    {
        return "func2 exception";
    }
};

void func2()
{
    throw func2_exception();
}

void func1()
{
    try
    {
        func2();
    }
    catch(std::exception& e)
    {
        throw func2_exception(e); // <--- is this correct? will the temporary object will be alive?
    }
}

int main(void)
{
    try
    {
        func1();
    }
    catch(base_exception& e)
    {
        std::cout << "Got exception" << std::endl;
        std::cout << e.what();
        std::cout << "InnerException" << std::endl;
        std::cout << e.InnerException.what(); // <---- how to make sure it has inner exception ?
    }
}

В приведенном выше листинге кода я не уверен, как инициализировать элемент «InnerException», когда нет внутреннего исключения. Также я не уверен, выживет ли временный объект, брошенный из func1, даже после броска func2?

Ответы [ 6 ]

3 голосов
/ 14 мая 2010

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

1 голос
/ 14 мая 2010

Также я не уверен, что временный объект, который выбрасывается из func1 выживет даже после func2 бросить? * * 1002

Нет. Если вы не сбросите исключение с throw;. Вы можете реализовать это, если разрешите только некоторый (ограниченный) набор типов исключений.

0 голосов
/ 07 августа 2018

Начиная с C ++ 11 у вас есть новые опции:

  1. Вы можете использовать std :: exception_ptr .

    Затем исключение сохраняется до последнегоисключение_ptr для этого исключения уничтожено.

    struct base_exception : public std::exception
    {
        std::exception_ptr InnerException;
    
        base_exception() {}
        base_exception(std::exception& innerException)
         : InnerException(std::make_exception_ptr(innerException))
        {}
    
    };
    
  2. Или вы можете просто использовать std :: nested_exception .
0 голосов
/ 15 июля 2014

Как утверждают другие, boost :: exception - хорошая опция. Однако, как и все опции, которые используют подход общего базового класса, они полагаются на все сгенерированные исключения, производные от этого базового класса. Если вашим промежуточным обработчикам уловов необходимо добавить информацию об исключении из сторонней библиотеки, это не сработает.

Опциональным вариантом может быть использование промежуточных обработчиков перехвата, подобных этому:

catch (std::exception& ex)
{
   std::string msg = ex.what();
   msg.append(" - my extra info");
   ex = std::exception(msg.c_str()); // slicing assignment
   throw;                            // re-throws 'ex', preserving it's original type
}

Это работает только для реализаций std :: exception, которые предоставляют конструктор, принимающий строковый параметр (например, VC ++). Конструктор std :: exception, принимающий строку, является нестандартным расширением.

0 голосов
/ 14 мая 2010

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

Это можно (в некоторой степени) облегчить, фактически управляя временем жизни исключения и предоставляя полиморфные копии.

// Base class
class exception: virtual public std::exception, private boost::noncopyable
{
public:
  virtual exception* clone() const = 0;
  virtual void rethrow() const = 0; // throw most Derived copy
};

// ExceptionPointer
class ExceptionPointer: virtual public std::exception
{
public:
  typedef std::unique_ptr<exception> pointer;

  ExceptionPointer(): mPointer() {}
  ExceptionPointer(exception* p): mPointer(p) {}
  ExceptionPointer(pointer p): mPointer(p) {}

  exception* get() const { return mPointer.get(); }
  void throwInner() const { if (mPointer.get()) mPointer->rethrow(); }

  virtual char* what() const { return mPointer.get() ? mPointer->what() : 0; }

private:
  pointer mPointer;
};

Как использовать?

try
{
  // some code
}
catch(exception& e)
{
  throw ExceptionPointer(e.clone());
}

// later on
try
{
}
catch(ExceptionPointer& e)
{
  e.throwInner();
}
0 голосов
/ 14 мая 2010
//inversion of the problem :)
struct base_exception : public std::exception
{
    std::list<base_exception*> snowball;

    base_exception() { }
    void add(base_exception* e) { snowball.push_back(e); }
};

void func2()
{
    func2_exception e;
    e.add(new func2_exception());
    throw e;
}

void func1()
{
    try
    {
        func2();
    }
    catch(base_exception& e)
    {
        e.add(new func1_exception());
        throw e; 
    }
}
int main(void)
{
    try
    {
        func1();
    }
    catch(base_exception& e)
    {
        std::cout << "Got exception" << std::endl;
        //print info in the direct order of exceptions occurence
        foreach(base_exception* exception, e.snowball)
        {
              std::cout << exception->what();
              std::cout << "next exception was:" << std::endl;
        }
    }
}

хммм ...

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