C++ 重写函数的异常规范比基本版本更宽松

C++ 重写函数的异常规范比基本版本更宽松,c++,exception,c++14,C++,Exception,C++14,我想自定义一个异常类,代码如下: class TestException : std::exception{ public: const char *what() const override { return "TestException"; } }; 我使用了Clion,IDE在函数what()上给了我一个警告:覆盖函数的异常规范比基本版本更宽松 但是如果我用gcc构建代码,就不会出现任何警告。 我用C++ 14,GCC 5.5.0 有人能解释一下警告的含义吗?我能忽略

我想自定义一个异常类,代码如下:

class TestException : std::exception{
  public:
  const char *what() const override {
    return "TestException";
  }
};
我使用了Clion,IDE在函数
what()
上给了我一个警告:
覆盖函数的异常规范比基本版本更宽松

但是如果我用gcc构建代码,就不会出现任何警告。 我用C++ 14,GCC 5.5.0


有人能解释一下警告的含义吗?我能忽略它吗?

自C++11以来,
std::exception
的成员函数被声明为
noexcept
。因此,您也应该使覆盖的
what
noexcept
。(实际上,这就是错误消息所说的。)


请注意,
noexcept
关键字必须位于
override
关键字之前(请参见,例如,了解详细信息)。

您面临的警告与您正在使用C++14这一事实有关,如果您要使用C++17编译,则这将成为一个错误。因此,我不建议忽略它

发生什么事了

std::exception
将方法
what
定义为:
virtual const char*what()const noexcept。您继承此方法并重新实现它,而不指定
noexcept
。结果是,您告诉您的实现可以抛出异常,而基本方法指出这不应该抛出异常。(打电话的人会这样认为)

这在C++17中已修复,它使
noexcept
成为类型系统的一部分,并要求您修复此代码:

const char *what() const noexcept override
from
std::exception
是一个
虚拟
函数,派生类中的
虚拟
函数的异常规范不能比它在基类中重写的函数更宽松

本标准“例外规范”一节中提到了这一点

18.4例外规范[例外.spec]

4.如果虚拟函数具有非抛出异常规范,则在任何派生类中重写该虚拟函数的任何函数的所有声明(包括定义)均应具有非抛出异常规范,除非重写函数定义为已删除

给出的示例(与问题中的代码有些类似)也说明了这一点

struct B 
{ 
  virtual void f() noexcept; 
  virtual void g(); 
  virtual void h() noexcept = delete; 
};
struct D: B 
{ 
  void f(); // ill-formed 
  void g() noexcept; // OK 
  void h() = delete; // OK 
}; 
D::f
的声明格式不正确,因为它具有潜在的引发异常规范,而
B::f
具有非引发异常规范

解决方案是更改代码,如:

class TestException : std::exception{
  public:
  const char *what() const noexcept override {
    return "TestException";
  }
};

请参见此处。

可能是缺少
noexcept
?作为旁注,我建议继承
std::logic_error
std::runtime_error
,它更具体,还允许您在构造时正确设置错误消息。基类负责
what()
。惰性格式通常是一个坏主意,因为(例如)我在对P.W.答案的评论中给出的原因。你没有提到的是
What()
noexcept
的一个非常明显的原因–在试图找出其他异常是什么的时候引发异常会非常烦人。这强烈阻止了对异常消息的延迟格式化,这也可能是为什么
what()
不返回
std::string
(复制时可能会抛出)。