una - subprogramas virtuales c++
Anulando una funciĆ³n virtual[ (3)
Considera lo que realmente estás diciendo:
class B
{
public:
[[noreturn]] virtual void f() { throw std::runtime_error(""); }
};
Ciertamente, el lector humano, y posiblemente el compilador, interpretaría esto como un "contrato", es decir,
" f()
no volveré, lo prometo"
Eso debería aplicarse a las anulaciones de f()
también, o de lo contrario está incumpliendo el contrato.
El estándar podría no estar bien especificado en esto, pero incluso si funciona, lo recomendaría en función de la legibilidad.
El atributo [[noreturn]]
se puede aplicar a funciones que no están destinadas a devolver. Por ejemplo:
[[noreturn]] void will_throw() { throw std::runtime_error("bad, bad, bad ...."); }
Pero me he encontrado con la siguiente situación (no, no diseñé esto):
class B {
public:
virtual void f() { throw std::runtime_error(""); }
};
class D : public B {
void f() override { std::cout << "Hi" << std::endl; }
};
Realmente me gustaría colocar el atributo [[noreturn]]
en la declaración B::f()
. Pero no tengo claro qué sucede con la anulación en la clase derivada. El retorno exitoso de una función [[noreturn]]
da como resultado un comportamiento indefinido, y ciertamente no quiero eso si una anulación también hereda el atributo.
La pregunta: Al invalidar [[noreturn] virtual void B::f()
, ¿Heredo el atributo [[noreturn]]
?
He revisado el estándar C ++ 14 y tengo problemas para determinar si los atributos se heredan.
En la práctica, ni g++ , clang ni MSVC consideran el atributo [[noreturn]]
como heredado
#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();
}
que imprime "B", "D" y "D" para los tres compiladores.
He revisado el estándar, y no hay ninguna indicación de que [[noreturn]]
específicamente, o los atributos en general, sean "heredados" al anular las funciones.
Es difícil demostrar que es negativo, y el estándar en realidad no lo declara de ninguna manera, pero como A::f()
y B::f()
son funciones distintas y el único comportamiento descrito se define en términos de funciones, Creo que estás seguro de marcar A::f()
como [[noreturn]]
.
Dicho esto, no puedo imaginar qué optimización útil podría realizar posteriormente el compilador, dado el envío dinámico.