sho*_*tsy 5 c++ gcc exception derived object-slicing
我正在为我的库设计一个C++的异常层次结构."层次结构"是从std :: runtime_error派生的4个类.我想避免异常类的切片问题,因此使复制构造函数受到保护.但显然gcc需要在抛出它们的实例时调用复制构造函数,因此抱怨受保护的复制构造函数.Visual C++ 8.0编译相同的代码.是否有任何可移植的方法来解决异常类的切片问题?标准是否说明实现是否可以/应该要求抛出要抛出的类的复制构造函数?
Tho*_*mas 15
您的异常需要有一个公共拷贝构造函数.编译器必须能够复制它以便异常处理才能工作.
您的问题的解决方案是始终通过引用捕获:
try {
// some code...
throw MyException("lp0 is on fire!");
} catch (MyException const &ex) {
// handle exception
}
Run Code Online (Sandbox Code Playgroud)
(const-ness是可选的,但我总是把它放进去,因为很少需要修改异常对象.)
小智 9
托马斯的答案是正确的,但我也建议你不要浪费你的时间"设计一个异常层次结构".设计类层次结构是一个特别糟糕的想法,特别是当您可以从C++标准异常类中简单地派生出一对(并且不多于)新的异常类型时.
我会避免设计与您的库不同的异常层次结构.std::exception尽可能使用层次结构,并始终从该层次结构中的某些内容派生异常.你可能想读马歇尔克莱恩公司的C的异常部分++ FAQ -阅读FAQ 17.6,17.9,17.10和17.12尤其如此.
至于"强迫用户引用",我不知道这样做的好方法.我在一个小时左右的比赛中得出的唯一方法(周日下午)基于多态投掷:
class foo_exception {
public:
explicit foo_exception(std::string msg_): m_msg(msg_) {}
virtual ~foo_exception() {}
virtual void raise() { throw *this; }
virtual std::string const& msg() const { return m_msg; }
protected:
foo_exception(foo_exception const& other): m_msg(other.m_msg) {}
private:
std::string m_msg;
};
class bar_exception: public foo_exception {
public:
explicit bar_exception(std::string msg_):
foo_exception(msg_), m_error_number(errno) {}
virtual void raise() { throw *this; }
int error_number() const { return m_error_number; }
protected:
bar_exception(bar_exception const& other):
foo_exception(other), m_error_number(other.m_error_number) {}
private:
int m_error_number;
};
Run Code Online (Sandbox Code Playgroud)
这个想法是使复制构造函数受到保护并强制用户调用Class(args).raise()而不是throw Class(args).这使您可以抛出一个多态绑定的异常,您的用户只能通过引用捕获它.任何按值捕获的尝试都应该得到一个很好的编译器警告.就像是:
foo.cpp:59:错误:'bar_exception :: bar_exception(const bar_exception&)'受到保护
foo.cpp:103:错误:在此上下文中
当然这一切都是有代价的,因为你不能再throw明确使用,或者你会遇到类似的编译器警告:
foo.cpp:在函数'void h()'中:
foo.cpp:31:错误:'foo_exception :: foo_exception(const foo_exception&)'受到保护
foo.cpp:93:错误:在此上下文中
foo.cpp:31:错误:'foo_exception :: foo_exception(const foo_exception&)'受到保护
foo.cpp:93:错误:在此上下文中
总的来说,我会依赖编码标准和文档,说明你应该总是通过引用来捕获.确保您的库捕获它通过引用处理的异常并抛出新对象(例如,throw Class(constructorArgs)或throw;).我希望其他C++程序员具有相同的知识 - 但只是为了确保在任何文档中添加注释.
| 归档时间: |
|
| 查看次数: |
2135 次 |
| 最近记录: |