Учитывая внимание на этот вопрос/ответ получает, и ценную обратную связь от GManNickG, я очистил код немного. Даны две версии: одна с функциями C++ 11 и другая с только функциями C++ 98.
В файле Тип.HPP
#ifndef TYPE_HPP
#define TYPE_HPP
#include <string>
#include <typeinfo>
std::string demangle(const char* name);
template <class T>
std::string type(const T& t) {
return demangle(typeid(t).name());
}
#endif
В файле type.cpp (требуется C++ 11)
#include "type.hpp"
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>
std::string demangle(const char* name) {
int status = -4; // some arbitrary value to eliminate the compiler warning
// enable c++11 by passing the flag -std=c++11 to g++
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return (status==0) ? res.get() : name ;
}
#else
// does nothing if not g++
std::string demangle(const char* name) {
return name;
}
#endif
Использование:
#include <iostream>
#include "type.hpp"
struct Base { virtual ~Base() {} };
struct Derived : public Base { };
int main() {
Base* ptr_base = new Derived(); // Please use smart pointers in YOUR code!
std::cout << "Type of ptr_base: " << type(ptr_base) << std::endl;
std::cout << "Type of pointee: " << type(*ptr_base) << std::endl;
delete ptr_base;
}
Он печатает:
Тип ptr_base: Base*
Тип pointee: Derived
Испытано с г ++ 4.7.2, G ++ 4.9.0 20140302 (экспериментальный), лязг ++ 3.4 (ствол 184647), лязг 3.5 (ствол 202594) на Linux 64 бит и G ++ 4.7.2 (Mingw32, Win32 XP SP2).
Если вы не можете использовать C++ 11 функций, вот как это может быть сделано в C++ 98, файл type.cpp Сейчас:
#include "type.hpp"
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>
struct handle {
char* p;
handle(char* ptr) : p(ptr) { }
~handle() { std::free(p); }
};
std::string demangle(const char* name) {
int status = -4; // some arbitrary value to eliminate the compiler warning
handle result(abi::__cxa_demangle(name, NULL, NULL, &status));
return (status==0) ? result.p : name ;
}
#else
// does nothing if not g++
std::string demangle(const char* name) {
return name;
}
#endif
(Обновление от 8 сентября, 2013)
The accepted answer (as of Sep 7, 2013), когда вызов abi::__cxa_demangle()
успешно, возвращает указатель на локальный массив, выделенный стекем ... ouch!
Также обратите внимание, что если вы предоставляете буфер, abi::__cxa_demangle()
предполагает, что он будет выделен на кучу. Выделение буфера в стеке является ошибкой (из документа gnu): «Если output_buffer
недостаточно длинный, он расширяется, используя realloc
».Вызов realloc()
по указателю на стек ... ouch! (См. Также Igor Skochinsky 's kind comment.)
Вы можете легко проверить обе эти ошибки: просто уменьшите размер буфера в принятом ответе (по состоянию на 7 сентября 2013 г.) от 1024 до чего-то меньшего, например 16, и дать ему что-то с именем не дольше 15 (так realloc()
is не). Тем не менее, в зависимости от вашей системы и оптимизации компилятора, результатом будет: сбой мусора/ничего/программа.
Чтобы проверить вторую ошибку: установите размер буфера в 1 и вызовите его чем-то, чье имя длиннее 1 символа. Когда вы запускаете его, программа почти наверняка сработает, когда пытается вызвать realloc()
с указателем на стек.
(старый ответ от 27 декабря 2010 г.)
Важных изменений, внесенных в KeithB's code: буфер должен быть либо выделен таНосом или указан как NULL. НЕ размещайте его в стеке.
Разумно проверить этот статус.
Я не нашел HAVE_CXA_DEMANGLE
. Я проверяю __GNUG__
, хотя это не гарантирует, что код даже будет компилироваться. У кого-то есть лучшая идея?
#include <cxxabi.h>
const string demangle(const char* name) {
int status = -4;
char* res = abi::__cxa_demangle(name, NULL, NULL, &status);
const char* const demangled_name = (status==0)?res:name;
string ret_val(demangled_name);
free(res);
return ret_val;
}
Я взял, это устарело, в соответствии с сообщением, которое я получаю. – terminus 2008-11-11 20:10:40
Где вы нашли это сообщение? Я просто искал его и, похоже, поддерживал его, никаких доказательств того, что он устарел. – Ali 2010-12-27 20:22:09
Возможно, это устарело в :: пространстве имен. Используйте abi :: __ cxa_demangle, и вы не получите предупреждение. Какой gcc вы используете? – onitake 2011-07-29 01:03:33