Мне нравятся все ответы о том, как строка может быть статически размещена, но это не обязательно верно для всех реализаций, особенно для той, чья документация связана с оригинальным постером. В этом случае создается впечатление, что декорированное имя типа хранится статически для экономии места, а недекорированное имя типа вычисляется по требованию и кэшируется в связанном списке.
Если вам интересно, как реализация Visual C ++ type_info::name()
распределяет и кэширует свою память, выяснить несложно. Сначала создайте крошечную тестовую программу:
#include <cstdio>
#include <typeinfo>
#include <vector>
int main(int argc, char* argv[]) {
std::vector<int> v;
const type_info& ti = typeid(v);
const char* n = ti.name();
printf("%s\n", n);
return 0;
}
Соберите его и запустите под отладчиком (я использовал WinDbg) и посмотрите на указатель, возвращаемый type_info::name()
. Это указывает на глобальную структуру? Если это так, команда WinDbg ln
сообщит имя ближайшего символа:
0:000> ?? n
char * 0x00000000`00857290
"class std::vector<int,class std::allocator<int> >"
0:000> ln 0x00000000`00857290
0:000>
ln
ничего не печатал, что указывает на то, что строка не была в диапазоне адресов, принадлежащих какому-либо конкретному модулю. Он был бы в этом диапазоне, если бы он был в сегменте данных или данных только для чтения. Давайте посмотрим, был ли он выделен в куче, выполнив поиск во всех кучах по адресу, возвращенному type_info::name()
:
0:000> !heap -x 0x00000000`00857290
Entry User Heap Segment Size PrevSize Unused Flags
-------------------------------------------------------------------------------------------------------------
0000000000857280 0000000000857290 0000000000850000 0000000000850000 70 40 3e busy extra fill
Да, это было выделено в куче. Установка точки останова в начале malloc()
и перезапуск программы подтверждают это.
Просмотр объявления в <typeinfo>
дает представление о том, где кэшируются указатели кучи:
struct __type_info_node {
void *memPtr;
__type_info_node* next;
};
extern __type_info_node __type_info_root_node;
...
_CRTIMP_PURE const char* __CLR_OR_THIS_CALL name(__type_info_node* __ptype_info_node = &__type_info_root_node) const;
Если вы найдете адрес __type_info_root_node
и пройдете по списку в отладчике, вы быстро найдете узел, содержащий тот же адрес, который был возвращен type_info::name()
. Список, похоже, связан со схемой кэширования.
Страница MSDN, указанная в исходном вопросе, по-видимому, заполняет пробелы: имя сохраняется в его оформленной форме для экономии места, и эта форма доступна через type_info::raw_name()
. Когда вы впервые вызываете type_info::name()
для данного типа, он отменяет декорирование имени, сохраняет его в буфере, выделенном в куче, кэширует указатель буфера и возвращает его.
Связанный список может также использоваться для освобождения кэшированных строк при выходе из программы (однако я не проверял, так ли это). Это гарантирует, что они не будут отображаться как утечки памяти при запуске инструмента отладки памяти.