24

[[noreturn]]属性可以应用于不打算返回的函数。例如:

[[noreturn]] void will_throw() { throw std::runtime_error("bad, bad, bad ...."); }

但是我遇到了以下情况(不,我没有设计这个):

class B {
public:
  virtual void f() { throw std::runtime_error(""); }
};

class D : public B {
  void f() override { std::cout << "Hi" << std::endl; }
};

我真的很想将属性[[noreturn]]放在B::f()声明中。但我不清楚派生类中的覆盖会发生什么。从[[noreturn]]函数成功返回会导致未定义的行为,如果覆盖也继承了该属性,我当然不希望出现这种情况。

问题:通过覆盖[[noreturn] virtual void B::f(),我是否继承了该[[noreturn]]属性?

我查看了 C++14 标准,但无法确定属性是否被继承。

4

3 回答 3

12

我已经阅读了标准,没有迹象表明[[noreturn]]具体或更一般的属性是通过覆盖函数“继承”的。

很难证明是否定的,而且标准实际上并没有声明这一点,但是,因为A::f()B::f()仍然是不同的函数,并且描述的唯一行为是根据函数定义的,我认为你可以安全地标记A::f()[[noreturn]].

话虽如此,考虑到动态调度,我无法想象编译器随后可以执行哪些有用的优化。

于 2015-09-18T15:58:06.010 回答
5

在实践中,g++clangMSVC都不认为该[[noreturn]]属性是继承的

#include <iostream>

struct B {
public:
  [[noreturn]] virtual void f() { std::cout << "B\n"; throw 0; }
};

struct D : public B {
  void f() override { std::cout << "D\n"; }
};

int main() 
{
    try { B{}.f(); } catch(...) {}
    D{}.f();

    B* d = new D{};
    d->f();
}

它为所有三个编译器打印出“B”、“D”和“D”。

于 2015-09-18T19:33:47.127 回答
4

考虑一下你实际上在说什么:

class B
{
public:
    [[noreturn]] virtual void f() { throw std::runtime_error(""); }
};

当然,人类读者,可能还有编译器,会将此解释为“合同”,即
f()我保证不会返回”

然后,这也应该适用于覆盖f(),否则您将违反合同。

该标准可能对此没有指定,但即使它有效,我也会根据可读性建议反对它。

于 2015-09-18T16:12:49.463 回答