Поймать несколько пользовательских исключений? - C ++ - PullRequest
42 голосов
/ 25 марта 2010

Я учусь в своем первом классе программирования C ++, и я работаю над проектом, в котором нам нужно создать несколько пользовательских классов исключений, а затем в одном из наших обработчиков событий использовать блок try/catch для обработки их соответственно.

Мой вопрос: как мне перехватить мои несколько пользовательских исключений в моем блоке try/catch? GetMessage() - это пользовательский метод в моих классах исключений, который возвращает объяснение исключения как std::string. Ниже я включил весь соответствующий код из моего проекта.

Спасибо за помощь!

блок try / catch


    // This is in one of my event handlers, newEnd is a wxTextCtrl
try {
    first.ValidateData();
    newEndT = first.ComputeEndTime();
    *newEnd << newEndT;
}
catch (// don't know what do to here) {
    wxMessageBox(_(e.GetMessage()), 
                 _("Something Went Wrong!"),
                 wxOK | wxICON_INFORMATION, this);;
}

Метод ValidateData ()


void Time::ValidateData()
{
    int startHours, startMins, endHours, endMins;

    startHours = startTime / MINUTES_TO_HOURS;
    startMins = startTime % MINUTES_TO_HOURS;
    endHours = endTime / MINUTES_TO_HOURS;
    endMins = endTime % MINUTES_TO_HOURS;

    if (!(startHours <= HOURS_MAX && startHours >= HOURS_MIN))
        throw new HourOutOfRangeException("Beginning Time Hour Out of Range!");
    if (!(endHours <= HOURS_MAX && endHours >= HOURS_MIN))
        throw new HourOutOfRangeException("Ending Time Hour Out of Range!");
    if (!(startMins <= MINUTE_MAX && startMins >= MINUTE_MIN))
        throw new MinuteOutOfRangeException("Starting Time Minute Out of    Range!");
    if (!(endMins <= MINUTE_MAX && endMins >= MINUTE_MIN))
        throw new MinuteOutOfRangeException("Ending Time Minute Out of Range!");
    if(!(timeDifference <= P_MAX && timeDifference >= P_MIN))
        throw new PercentageOutOfRangeException("Percentage Change Out of Range!");
    if (!(startTime < endTime))
        throw new StartEndException("Start Time Cannot Be Less Than End Time!");
}

Только один из моих пользовательских классов исключений, остальные имеют такую ​​же структуру, как этот


class HourOutOfRangeException
{
public:
        // param constructor
        // initializes message to passed paramater
        // preconditions - param will be a string
        // postconditions - message will be initialized
        // params a string
        // no return type
        HourOutOfRangeException(string pMessage) : message(pMessage) {}
        // GetMessage is getter for var message
        // params none
        // preconditions - none
        // postconditions - none
        // returns string
        string GetMessage() { return message; }
        // destructor
        ~HourOutOfRangeException() {}
private:
        string message;
};

Ответы [ 7 ]

51 голосов
/ 25 марта 2010

Если у вас есть несколько типов исключений, и предполагается, что существует иерархия исключений (и все они публично получены из некоторого подкласса std::exception,), начните с самого конкретного и продолжите к более общему:

try
{
    // throws something
}
catch ( const MostSpecificException& e )
{
    // handle custom exception
}
catch ( const LessSpecificException& e )
{
    // handle custom exception
}
catch ( const std::exception& e )
{
    // standard exceptions
}
catch ( ... )
{
    // everything else
}

С другой стороны, если вас интересует только сообщение об ошибке - throw то же исключение, скажем std::runtime_error с другими сообщениями, а затем catch, что:

try
{
    // code throws some subclass of std::exception
}
catch ( const std::exception& e )
{
    std::cerr << "ERROR: " << e.what() << std::endl;
}

Также помните - бросить по значению, поймать по ссылке [const].

10 голосов
/ 25 марта 2010

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

class BaseException { };
class HourOutOfRangeException : public BaseException { };
class MinuteOutOfRangeException : public BaseException { };

Затем вы можете поймать их всех в одном блоке захвата:

catch (const BaseException& e) { }

Если вы хотите иметь возможность звонить GetMessage, вам нужно либо:

  • поместите эту логику в BaseException или
  • сделать GetMessage виртуальной функцией-членом в BaseException и переопределить ее в каждом из производных классов исключений.

Вы также можете рассмотреть возможность получения ваших исключений из одного из исключений стандартной библиотеки, например std::runtime_error, и использовать функцию-член idiomatic what() вместо GetMessage().

1 голос
/ 25 марта 2010

Получите все ваши исключения из общего базового класса BaseException, который имеет виртуальный метод GetMessage().

Тогда catch(const BaseException& e).

0 голосов
/ 28 января 2019

Я столкнулся с той же проблемой, и вот что я закончил:

  std::shared_ptr<MappedImage> MappedImage::get(const std::string & image_dir,
                                                const std::string & name,
                                                const Packet::Checksum & checksum) {
    try {
      return std::shared_ptr<MappedImage>(images_.at(checksum));
    } catch (std::out_of_range) {
    } catch (std::bad_weak_ptr) {
    }
    std::shared_ptr<MappedImage> img =
      std::make_shared<MappedImage>(image_dir, name, checksum);
    images_[checksum_] = img;
    return img;
  }

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

0 голосов
/ 27 февраля 2018

</p>

#include <iostream> 
void test(int x)`
{
try{
if(x==1)
throw (1);
else if(x==2)
    throw (2.0);
}
catch(int a)
{
cout<<"It's Integer";
}
catch(double b)
{
cout<<"it's Double";
}
}
int main(){
cout<<" x=1";
test(1);
cout<<"X=2";
test(2.0);
return 0;
}`
0 голосов
/ 12 сентября 2016

Когда шаблоны не могут, макросы сохраняют день.Решение взято из Boost .Кипит до 7 строк кода.

/// @file multicatch.hpp
#include <boost/preprocessor/variadic/to_list.hpp>
#include <boost/preprocessor/list/for_each.hpp>

/// Callers must define CATCH_BODY(err) to handle the error,
/// they can redefine the CATCH itself, but it is not as convenient. 
#define CATCH(R, _, T) \
  catch (T & err) {    \
    CATCH_BODY(err)    \
  }
/// Generates catches for multiple exception types
/// with the same error handling body.
#define MULTICATCH(...) \
  BOOST_PP_LIST_FOR_EACH(CATCH, _, BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__))
// end of file multicatch.hpp

/// @file app.cc
#include "multicatch.hpp"

// Contrived example.
/// Supply the error handling logic.
#define CATCH_BODY(err)                        \
  log() << "External failure: " << err.what(); \
  throw;

void foo() {
  try {
    bar();  // May throw three or more sibling or unrelated exceptions.
  }
  MULTICATCH(IOError, OutOfMemory)
}

#undef CATCH_BODY
0 голосов
/ 11 сентября 2016

У меня была похожая проблема сегодня, но оказалось, что мне не нужно мое решение, чтобы решить мою проблему. Честно говоря, я не мог придумать реальные варианты использования (ведение журнала?), И я не нашел в нем особого смысла.

В любом случае, это подход со списками типов (требуется C ++ 11). Я думаю, что преимущество этого подхода в том, что нет необходимости иметь общий базовый класс для пользовательских исключений (за исключением std :: exception, возможно?). Другими словами, это не мешает вашей иерархии исключений.

Могут быть некоторые тонкие ошибки, о которых я не знаю.

#include <type_traits>
#include <exception>

/// Helper class to handle multiple specific exception types
/// in cases when inheritance based approach would catch exceptions
/// that are not meant to be caught.
///
/// If the body of exception handling code is the same
/// for several exceptions,
/// these exceptions can be joined into one catch.
///
/// Only message data of the caught exception is provided.
///
/// @tparam T  Exception types.
/// @tparam Ts  At least one more exception type is required.
template <class T, class... Ts>
class MultiCatch;

/// Terminal case that holds the message.
/// ``void`` needs to be given as terminal explicitly.
template <>
class MultiCatch<void> {
 protected:
  explicit MultiCatch(const char* err_msg) : msg(err_msg) {}
  const char* msg;
};

template <class T, class... Ts>
class MultiCatch : public MultiCatch<Ts...> {
  static_assert(std::is_base_of<std::exception, T>::value, "Not an exception");

 public:
  using MultiCatch<Ts...>::MultiCatch;

  /// Implicit conversion from the guest exception.
  MultiCatch(const T& error) : MultiCatch<Ts...>(error.what()) {}  // NOLINT

  /// @returns The message of the original exception.
  const char* what() const noexcept {
    return MultiCatch<void>::msg;
  }
};

/// To avoid explicit ``void`` in the type list.
template <class... Ts>
using OneOf = MultiCatch<Ts..., void>;

/// Contrived example.
void foo() {
  try {
    bar();  // May throw three or more sibling or unrelated exceptions.
  } catch (const OneOf<IOError, OutOfMemory>& err) {
    log() << "External failure: " << err.what();

    throw;  // Throw the original exception.
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...