C++ 中的自定义异常:在哪里定义它们?

Custom exceptions in c++: where do I define them?

本文关键字:定义 在哪里 自定义异常 C++      更新时间:2023-10-16

对于我当前的项目,我定期定义要捕获的自定义异常。

但是,我正在努力确定有关这些异常定义的代码的最佳结构。

最初,我只是定义了嵌套在我的类中的异常来抛出它们,如下所示:

class Foo {
struct CustomException : public std::runtime_error {
}
void TrySomething() {
throw CustomException();
}
};

但是,现在我正在使用模板类,如果不提供模板参数,我就无法访问此异常。也就是说,我不能做:

template class <T>
class Foo {
struct CustomException : public std::runtime_error {
}
void TrySomething() {
throw CustomException();
}
};
void SomeFunction() {
try {
Foo foo;
foo.TrySomething();
}
catch (const Foo::CustomException& exc) {
}
}

因为没有模板参数的 Foo 不是一个类。 我试图找出最干净的解决方案是什么(可以选择重新设计项目的其余部分以遵循所选标准(。

想到的选项:

  • 为 Foo 创建一个接口并将异常类放在那里(这似乎有点过分,只是出于这个原因制作一个接口(
  • 将异常放在我专门为Foo制作的命名空间中
  • 将异常"free"放在Foo周围(但我猜测是在项目命名空间中,我现在的项目没有,但无论如何我都读过这是很好的做法(
  • 将所有异常放在单个文件、命名空间或结构中
  • 创建一个"异常"命名空间,并在我想添加一个命名空间时对其进行扩展(在引发异常的类文件中(

如果您的异常确实与模板类密不可分,但独立于模板的特定实例化,则使用类似

struct FooBase
{
struct FooBaseException : public std::exception
{
};
};
template class <T> 
struct Foo : FooBase
{
};

是一种方式。空基类优化将适用,至少从概念上讲,您已经在模板实例化之间引入了一些关系。

展望未来,您可能会发现常见函数出现在基类中。

这种模式在 1990 年代很常见,模板可能会导致代码膨胀,但我也看到了它在这个特定实例中的用途。

我真的不明白为什么你需要为你的例外做模板。 我相信该代码将满足您的所有需求。您可以为常用异常创建枚举,也可以增加单个自定义异常。

enum class ErrorCode {
kErrorOne,
};

// Helper function to get an explanatory string for error
inline std::string GetErrorString(ErrorCode error_code) {
switch (error_code) {
case ErrorCode::kErrorOne:
return "Some error";
}
return {};
}
class CustomException : public std::runtime_error {
public:
explicit CustomException(ErrorCode error_code) : std::runtime_error{GetErrorString(error_code)} {}
CustomException(const std::string& what)
: std::runtime_error{what} {}    
};

另外,你可以看看这里,一个非常相似的问题