6 Stimmen

Hat C++ bereits eine Art von Reflektion?

Betrachten Sie dieses Beispiel:

struct Nobody_Expects_The_Spanish_Inquisition{};

int main(){
    throw Nobody_Expects_The_Spanish_Inquisition();
}

Ausgabe auf Ideone angezeigt:

terminate called after throwing an instance of Nobody_Expects_The_Spanish_Inquisition'

Ähnliche Ausgabe für Windows:

Nicht behandelte Ausnahme bei 0x760fb727 in Test.exe: Microsoft C++ Ausnahme: Nobody_Expects_The_Spanish_Inquisition am Speicherort 0x001ffea3..

Wie man sehen kann, scheint der endgültige Zusammenbau bereits den Namen der Ausnahme zu enthalten, oder es gibt eine andere Methode, um den Namen zu erwerben.

Kann dies als eine Art von Reflektion betrachtet werden? Oder ist es abhängig vom Compiler/Betriebssystem, ob der Name der Ausnahme tatsächlich angezeigt werden kann?

7voto

Es hängt vom Compiler ab. Offensichtlich ist es für den Compiler einfach, jede Ausnahme zu erkennen und den Typ jedes geworfenen Objekts in die ausführbare Datei zu kodieren. Aber es besteht keine Anforderung, dass dies getan werden muss.

Und wenn man darüber nachdenkt, müssen Ausnahmen in einen seltsamen implementationsabhängigen Speicher kopiert werden, wenn sie geworfen werden. Daher macht es Sinn, dass der Name ihres Typs über diesen Mechanismus für die Laufzeit eines bestimmten Compilers zugänglich ist.

3voto

Puppy Punkte 141483

Nein, es handelt sich nicht um Reflexion in irgendeiner sinnvollen Kapazität, nur um Debug-Symbole.

2voto

Luc Danton Punkte 34153

Wenn eine Ausnahme aus main entkommt, wird std::terminate aufgerufen, das wiederum den installierten Ausnahmebehandlungsprozedur aufruft. Wenn keine Ausnahmebehandlungsprozedur im Programm festgelegt wurde, wird die Standardausnahmebehandlungsprozedur aufgerufen. Die einzige Anforderung an diese Standardausnahmebehandlungsprozedur ist, dass sie std::abort aufruft. Dies bedeutet, dass eine Implementierung frei ist, eine hilfreiche Meldung zu drucken, bevor std::abort aufgerufen wird, was anscheinend hier der Fall ist.

Obwohl Reflexion oder Debug-Symbole oder RTTI ausreichen, um diese Fehlermeldung zu drucken, sind sie nicht notwendig: Die Implementierung kann jede Art von Schwarzmagie verwenden, egal wie tief sie ist.

0voto

Omnifarious Punkte 52299

Dieses Programm:

#include 
#include 

struct Nobody_Expects_The_Spanish_Inquisition {
};

namespace junk {
struct I_didnt_expect_a_kind_of_spanish_inquisition
   : public Nobody_Expects_The_Spanish_Inquisition
{
};
}

int main(int argc, const char *argv[])
{
   using ::std::type_info;
   using ::std::cout;

   Nobody_Expects_The_Spanish_Inquisition foo;
   junk::I_didnt_expect_a_kind_of_spanish_inquisition bar;
   const type_info &fooinfo = typeid(foo);
   const type_info &barinfo = typeid(bar);
   cout << "Der Typ von foo ist <" << fooinfo.name() << ">\n";
   cout << "Der Typ von bar ist <" << barinfo.name() << ">\n";
   return 0;
}

hat diese Ausgabe:

$ ./foo 
Der Typ von foo ist <38Nobody_Expects_The_Spanish_Inquisition>
Der Typ von bar ist 

Dies ist so gut wie es für Reflexionen in C++ wird. Und das reicht gerade aus, um das zu erreichen, was der Standard-Terminierungshandler tut.

Während der Standard-Terminierungshandler, wie andere schon angemerkt haben, sowieso das Ziel auf seine Weise erreichen darf, würde es mich überraschen, wenn er nicht die gleichen Mechanismen nutzen würde, die für die Implementierung von typeid verwendet werden, um dies zu ermöglichen.

Natürlich könnte der Standard-Terminierungshandler arbeiten, indem er auf einen speziellen Bereich zugreift, den der Compiler erstellt, wann immer eine Ausnahme geworfen wird, der aufzeichnet, was der Compiler über den Namen des Typs weiß, an der Stelle, an der sie geworfen wird. Wie andere angemerkt haben, ist der Standard-Terminierungshandler vom Compiler dort platziert und nicht an die Regeln gebunden, denen der von einem C++-Programmierer geschriebene Code folgen müsste.

Ich habe Leute gesehen, die ihre eigenen Terminierungshandler schreiben, die den Aufrufstapel manuell durchgehen und Debug-Symbole zu jeder Adresse nachschlagen, um eine Art Stack-Trace zu erhalten. Dies sind Compiler- und plattformspezifische Magie, und da der Compiler genau weiß, welcher Compiler es ist und auf welcher Plattform er verwendet wird, könnte er einen Standard-Terminierungshandler haben, der dasselbe auf unterstützten Plattformen tut.

Zusammenfassend: RTTI ist nicht erforderlich, um das von Ihnen festgestellte Feature zu implementieren. Aber RTTI ist eine sehr rudimentäre Form der Reflexion und könnte verwendet werden, um dieses Feature zu implementieren.

-1voto

Die "Reflexion" wird unter Verwendung von RTTI erstellt. Nichts Besonderes, nur der Name des Typs.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X