捕获多个自定义异常?- C++
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2512931/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Catch Multiple Custom Exceptions? - C++
提问by Alex
I'm a student in my first C++ programming class, and I'm working on a project where we have to create multiple custom exception classes, and then in one of our event handlers, use a try/catch
block to handle them appropriately.
我是我的第一个 C++ 编程课程的学生,我正在从事一个项目,我们必须创建多个自定义异常类,然后在我们的一个事件处理程序中,使用一个try/catch
块来适当地处理它们。
My question is: How do I catch my multiplecustom exceptions in my try/catch
block? GetMessage()
is a custom method in my exception classes that returns the exception explanation as a std::string
. Below I've included all the relevant code from my project.
我的问题是:如何在块中捕获多个自定义异常try/catch
?GetMessage()
是我的异常类中的一个自定义方法,它将异常解释作为std::string
. 下面我包含了我项目中的所有相关代码。
Thanks for your help!
谢谢你的帮助!
try/catch block
尝试/捕获块
// 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() Method
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!");
}
Just one of my custom exception classes, the others have the same structure as this one
只是我的自定义异常类之一,其他与此具有相同的结构
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;
};
回答by Nikolai Fetissov
If you have multiple exception types, and assuming there's a hierarchy of exceptions (and all derived publicly from some subclass of std::exception
,) start from the most specific and continue to more general:
如果您有多种异常类型,并假设有一个异常层次结构(并且所有异常都从 , 的某个子类公开派生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
}
On the other hand, if you are interested in just the error message - throw
same exception, say std::runtime_error
with different messages, and then catch
that:
另一方面,如果您只对错误消息感兴趣 -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;
}
Also remember - throw by value, catch by [const] reference.
还要记住 - 按值抛出,按 [const] 引用捕获。
回答by James McNellis
You should create a base exception class and have all of your specific exceptions derive from it:
您应该创建一个基本异常类,并从它派生所有特定的异常:
class BaseException { };
class HourOutOfRangeException : public BaseException { };
class MinuteOutOfRangeException : public BaseException { };
You can then catch all of them in a single catch block:
然后,您可以在单个 catch 块中捕获所有这些:
catch (const BaseException& e) { }
If you want to be able to call GetMessage
, you'll need to either:
如果您希望能够调用GetMessage
,则需要:
- place that logic into
BaseException
, or - make
GetMessage
a virtual member function inBaseException
and override it in each of the derived exception classes.
- 将该逻辑放入
BaseException
, 或 - 在每个派生的异常类中创建
GetMessage
一个虚拟成员函数BaseException
并覆盖它。
You might also consider having your exceptions derive from one of the standard library exceptions, like std::runtime_error
and use the idiomatic what()
member function instead of GetMessage()
.
您还可以考虑让您的异常派生自标准库异常之一,例如std::runtime_error
并使用惯用的what()
成员函数而不是GetMessage()
.
回答by Jesse Beder
Derive all of your exceptions from a common base class BaseException
that has a virtual method GetMessage()
.
从BaseException
具有虚方法的公共基类派生所有异常GetMessage()
。
Then catch(const BaseException& e)
.
然后catch(const BaseException& e)
。
回答by Goswin von Brederlow
I run into the same problem and here is what I ended up with:
我遇到了同样的问题,这是我最终得到的:
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;
}
In my case the function returns when it doesn't get an exception. So I don't actually have to do anything inside the catch but can do the work outside the try.
在我的情况下,该函数在没有异常时返回。所以我实际上不必在 catch 内做任何事情,但可以在 try 之外做任何工作。
回答by Olzhas Rakhimov
I had a similar problem today, but it turned out I didn't need my solution to solve my problem. Honestly, I couldn't think of real use cases (logging?), and I didn't find much use for it in my code.
我今天遇到了类似的问题,但结果证明我不需要我的解决方案来解决我的问题。老实说,我想不出真正的用例(日志记录?),而且我在我的代码中没有发现它有多大用处。
Anyway, this is an approach with type lists (requires C++11). I think the advantage of this approach is that there's no need to have a common base class for custom exceptions (except for std::exception, maybe?). In other words, it is not intrusive to your exception hierarchy.
无论如何,这是一种带有类型列表的方法(需要 C++11)。我认为这种方法的优点是不需要为自定义异常提供一个公共基类(除了 std::exception,也许?)。换句话说,它不会侵入您的异常层次结构。
There might be some subtle errors that I am not aware of.
可能有一些我不知道的细微错误。
#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.
}
}
回答by Olzhas Rakhimov
When templates can't, macros save the day. The solution is taken from Boost. It boils to 7 lines of code.
当模板不能时,宏可以挽救这一天。解决方案来自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
回答by Umet Ale
#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;
}`