Weißt du auch, warum?
type_info::name() ist in Visual C++ so definiert:
char const * name(
__type_info_node * __ptype_info_node = &__type_info_root_node
) const;
und __type_info_node ist wiederum die Datenstruktur einer verketteten Liste. Der Compiler durchsucht also alle Typinformationen in einer verketteten Liste, um den Namen zu finden. Dass das nicht wegoptimiert werden kann, wundert dann auch nicht mehr.
(Außerdem macht mich das fehlende const jedes Mal verrückt, wenn ich refactoren möchte!)
Ach nein; es ist viel lustiger:
http://stackoverflow.com/questions/200857/caching-a-const-char-as-a-return-type hat geschrieben:The MSDN page linked in the original question seems to fill in the blanks: the name is stored in its decorated form to save space, and this form is accessible via type_info::raw_name(). When you call type_info::name() for the first time on a given type, it undecorates the name, stores it in a heap-allocated buffer, caches the buffer pointer, and returns it.
<3
Man könnte nun versucht sein,
raw_name() zu nutzen. Leider kommt das aber aus der Laufzeitbibliothek und wird nicht statisch gebunden. Aber ein Sprung in die Funktion verrät:
Code: Alles auswählen
mov qword ptr [rsp+8],rcx
mov rax,qword ptr [this]
add rax,10h
ret
Die Funktion tut nichts anderes, als den Speicher 16 Bytes hinter dem
this-Zeiger zurückzugeben. Mal gucken, ob wir das auch selber hinkriegen:
auto const & foo = typeid(char);
foo auf den Debugger gezogen enthüllt die Namen der Datenstruktur:
- foo {_M_data=0x0000000000000000 _M_d_name=0x000000013f90c028 ".D" } const type_info &
+ __vfptr 0x000000013f8bdbd0 const type_info::`vftable' *
_M_data 0x0000000000000000 void *
+ _M_d_name 0x000000013f90c028 ".D" char [1]
Also schnell eine eigene
type_info gebaut:
extern struct __type_info_node __type_info_root_node;
class type_info {
public:
__declspec(dllimport) bool operator == (
type_info const &
) const noexcept;
__declspec(dllimport) bool operator != (
type_info const &
) const noexcept;
__declspec(dllimport) int before(
type_info const &
) const noexcept;
__declspec(dllimport) char const * name(
__type_info_node * __ptype_info_node = &__type_info_root_node
) const;
// define here instead of importing it from the C run-time library
// (does this cause memory leaks if 'name()' was called? I don't fucking care)
virtual ~type_info() noexcept { }
// (specific to Visual C++ 2010)
size_t hash_code() const noexcept { … }
// define here instead of importing it from the C run-time library (specific to Visual C++ 2010)
char const * raw_name() const noexcept {
return _M_d_name;
}
private:
type_info(type_info const &);
type_info & operator = (type_info const &);
void * _M_data;
char _M_d_name[1];
};
und schon wird
typeid(char).raw_name();
optimiert zu:
lea rdx,[char `RTTI Type Descriptor'+10h (13F05E080h)]
Dekoriert bringt er dir zwar nicht viel (bei mir lautet er
„.D“), aber zum Vergleichen reicht’s.
Bitteschön :)
Apopo Vergleichen (wollte nur mal
Popo sagen, hihihi): Meine telepathische Verbindung zur MSVCRT.DLL suggeriert mir, dass in
operator == (),
operator != () und
before() nur ein String-Vergleich beginnend bei Zeichen
[1] durchgeführt wird; und
strcmp() ist ja zum Glück ein Compiler-Intrinsic.
So. Jetzt stört nur noch der Virtual Function Table … leider kriegen wir den nicht aus der Klasse raus, weil Visual C++ die Daten für uns generiert und unsere Attribute dann verschoben wären. Jedoch: Eben WEIL Visual C++ die Daten für uns generiert, und da auch der VFT dazugehört; und der (virtuelle) D’tor niemals aufgerufen wird (die Daten sind ja statisch), können wir ein schönes
__declspec(novtable) vor die Deklaration klatschen. Damit wären nochmal 16 Bytes gespart (selbst dann, wenn das Programm nirgends
typeid() oder
dynamic_cast<>() nutzt).
Damit hättest du die schnellste Visual C++-Typinformation bei nicht-statischer Laufzeitbibliothek der Welt ;-)
Übrigens ist
das einer der Gründe, warum ich alles selber schreibe: Wenn jede Pisselfunktion aus einer DLL kommt, bringt LTCG einfach garnichts.