捕获多个自定义异常? - C++

Posted

技术标签:

【中文标题】捕获多个自定义异常? - C++【英文标题】:Catch Multiple Custom Exceptions? - C++ 【发布时间】:2011-01-31 13:25:56 【问题描述】:

我是第一个 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;
;

【问题讨论】:

不要抛出指针,省略新的。 看到你从现在到现在的进步真是太棒了,你是一个拥有超过 40k 代表的*** SO 用户。真的太棒了! 【参考方案1】:

如果您有多种异常类型,并假设有一个异常层次结构(并且所有异常都从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] 引用捕获。

【讨论】:

【参考方案2】:

您应该创建一个基异常类,并让您的所有特定异常都派生自它:

class BaseException  ;
class HourOutOfRangeException : public BaseException  ;
class MinuteOutOfRangeException : public BaseException  ;

然后您可以在一个 catch 块中捕获所有这些:

catch (const BaseException& e)  

如果您希望能够拨打GetMessage,您需要:

将该逻辑放入BaseException,或 使GetMessage 成为BaseException 中的虚拟成员函数,并在每个派生异常类中覆盖它。

您还可以考虑让您的异常派生自标准库异常之一,例如std::runtime_error,并使用惯用的what() 成员函数而不是GetMessage()

【讨论】:

@Alex:我不确定这是不是很好的建议。在一般情况下,您无法控制异常的定义(例如,它们来自某个库,例如 Boost)。 如果我抛出一个 int 怎么办?还是浮子?我应该将它们包装在 Int 或 Float 类中,然后从它们派生吗?【参考方案3】:

如果模板不能,宏可以节省时间。 解决方案取自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

【讨论】:

【参考方案4】:

从具有虚拟方法 GetMessage() 的公共基类 BaseException 派生所有异常。

然后catch(const BaseException&amp; e)

【讨论】:

【参考方案5】:

我今天遇到了类似的问题,但事实证明我不需要我的解决方案来解决我的问题。老实说,我想不出真正的用例(日志记录?),而且我在我的代码中没有发现它有多大用处。

无论如何,这是一种使用类型列表的方法(需要 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.
  

【讨论】:

代码不起作用。我没有注意测试。这只是一厢情愿。 catch 中不考虑隐式转换。【参考方案6】:

我遇到了同样的问题,结果如下:

  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;
  

在我的情况下,函数在没有异常时返回。所以我实际上不必在 catch 内做任何事情,但可以在 try 之外做任何工作。

【讨论】:

【参考方案7】:

当您无法控制异常的类层次结构并且无法复制 catch 块的内容时,解决此问题的另一种方法是使用 dynamic_cast 像这样:

try

   ...

catch (std::exception& e)

    if(   nullptr == dynamic_cast<exception_type_1*> (&e)
       && nullptr == dynamic_cast<exception_type_2*> (&e))
    
        throw;
    
    // here you process the expected exception types

【讨论】:

【参考方案8】:

#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; `

【讨论】:

以上是关于捕获多个自定义异常? - C++的主要内容,如果未能解决你的问题,请参考以下文章

包含多个异常的自定义异常:鼓励还是不鼓励?

Springboot+自定义注解+自定义AOP前置增强+自定义异常+自定义异常捕获

Java -- 异常的捕获及处理 -- 自定义异常类

自定义异常 - 捕获不继承自 BaseException 的类

java中Debug调试异常的概念异常体系处理异常的关键字try/catch/finally/throw/throws多个异常使用捕获并处理的方式继承关系中处理异常自定义异常类

java中Debug调试异常的概念异常体系处理异常的关键字try/catch/finally/throw/throws多个异常使用捕获并处理的方式继承关系中处理异常自定义异常类