std :: type_info :: name 결과 관리 해제
저는 현재 호출 함수에 대한 정보를 인쇄하는 로깅 코드를 작업 중입니다. 이것은 비교적 쉬울 것입니다. 표준 C ++에는 type_info
클래스가 있습니다. 여기에는 typeid의 클래스 / 함수 / 등의 이름이 포함됩니다. 그러나 그것은 엉망입니다. 별로 유용하지 않습니다. 즉 typeid(std::vector<int>).name()
돌아갑니다 St6vectorIiSaIiEE
.
이것에서 유용한 것을 생산하는 방법이 있습니까? 마찬가지로 std::vector<int>
위의 예를 들어. 템플릿이 아닌 클래스에서만 작동한다면 괜찮습니다.
솔루션은 gcc에서 작동하지만 포팅 할 수 있다면 더 좋을 것입니다. 로깅 용이므로 끌 수 없을 정도로 중요하지는 않지만 디버깅에 도움이됩니다.
이 질문 / 답변에 대한 관심과 GManNickG 의 귀중한 피드백을 감안할 때 코드를 약간 정리했습니다. 두 가지 버전이 제공됩니다. 하나는 C ++ 11 기능이 있고 다른 하나는 C ++ 98 기능 만 있습니다.
파일 type.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
Linux 64 비트에서 g ++ 4.7.2, g ++ 4.9.0 20140302 (시험용), clang ++ 3.4 (트렁크 184647), clang 3.5 (트렁크 202594) 및 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
(2013 년 9 월 8 일 업데이트)
허용 된 답변 (2013 년 9 월 7 일 현재) ,에 대한 호출 abi::__cxa_demangle()
이 성공 하면 로컬 스택 할당 배열에 대한 포인터를 반환합니다 . 아야!
또한 버퍼를 제공 abi::__cxa_demangle()
하면 힙에 할당 된 것으로 간주합니다. 스택에 버퍼를 할당하는 것은 버그입니다 (gnu 문서에서) : " output_buffer
길이가 충분하지 않으면를 사용하여 확장됩니다 realloc
." 스택에 대한 포인터를 호출 realloc()
하는 중 ... 아야! ( Igor Skochinsky 의 친절한 의견 도 참조하십시오 .)
단지 예 16, 작은 일 1024에서 SEP ((7), 2013) 허용 대답에 버퍼 크기를 줄이고, 이름으로 뭔가를 줄 : 당신은 쉽게 이러한 버그를 모두 확인할 수 없습니다 때문에 (이상 15 일 realloc()
입니다 호출 되지 않음 ). 그래도 시스템 및 컴파일러 최적화에 따라 출력은 쓰레기 / 없음 / 프로그램 충돌입니다.
두 번째 버그를 확인하려면 버퍼 크기를 1로 설정하고 이름이 1 자보다 긴 것으로 호출합니다. 실행 realloc()
하면 스택에 대한 포인터로 호출 을 시도 할 때 프로그램이 거의 확실하게 충돌 합니다.
(2010 년 12 월 27 일의 이전 답변)
KeithB의 코드에 대한 중요한 변경 사항 : 버퍼는 malloc에 의해 할당되거나 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;
}
부스트 코어에는 디맨 글러가 포함되어 있습니다. core / demangle.hpp 체크 아웃 :
#include <boost/core/demangle.hpp>
#include <typeinfo>
#include <iostream>
template<class T> struct X
{
};
int main()
{
char const * name = typeid( X<int> ).name();
std::cout << name << std::endl; // prints 1XIiE
std::cout << boost::core::demangle( name ) << std::endl; // prints X<int>
}
기본적으로 abi::__cxa_demangle
이전에 제안 된대로를 위한 래퍼입니다 .
이것이 우리가 사용하는 것입니다. HAVE_CXA_DEMANGLE은 사용 가능한 경우에만 설정됩니다 (최신 버전의 GCC 만 해당).
#ifdef HAVE_CXA_DEMANGLE
const char* demangle(const char* name)
{
char buf[1024];
unsigned int size=1024;
int status;
char* res = abi::__cxa_demangle (name,
buf,
&size,
&status);
return res;
}
#else
const char* demangle(const char* name)
{
return name;
}
#endif
여기에서 원하는 것을 수행하는 함수가 포함 된 type_strings.hpp를 살펴보십시오 .
If you just look for a demangling tool, which you e.g. could use to mangle stuff shown in a log file, take a look at c++filt
, which comes with binutils. It can demangle C++ and Java symbol names.
Not a complete solution, but you may want to look at what some of the standard (or widely supported) macro's define. It's common in logging code to see the use of the macros:
__FUNCTION__
__FILE__
__LINE__
e.g.:
log(__FILE__, __LINE__, __FUNCTION__, mymessage);
It's implementation defined, so it's not something that's going to be portable. In MSVC++, name() is the undecorated name, and you have to look at raw_name() to get the decorated one.
Just a stab in the dark here, but under gcc, you might want to look at demangle.h
I also found a macro called __PRETTY_FUNCTION__
, which does the trick. It gives a pretty function name (figures :)). This is what I needed.
I.e. it gives me the following:
virtual bool mutex::do_unlock()
But I don't think it works on other compilers.
A slight variation on Ali's solution. If you want the code to still be very similar to
typeid(bla).name()
,
writing this instead
Typeid(bla).name()
(differing only in capital first letter)
then you may be interested in this:
In file type.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());
}
*/
class Typeid {
public:
template <class T>
Typeid(const T& t) : typ(typeid(t)) {}
std::string name() { return demangle(typ.name()); }
private:
const std::type_info& typ;
};
#endif
type.cpp stays same as in Ali's solution
Take a look at __cxa_demangle
which you can find at cxxabi.h
.
// KeithB's solution is good, but has one serious flaw in that unless buf is static
// it'll get trashed from the stack before it is returned in res - and will point who-knows-where
// Here's that problem fixed, but the code is still non-re-entrant and not thread-safe.
// Anyone care to improve it?
#include <cxxabi.h>
// todo: javadoc this properly
const char* demangle(const char* name)
{
static char buf[1024];
size_t size = sizeof(buf);
int status;
// todo:
char* res = abi::__cxa_demangle (name,
buf,
&size,
&status);
buf[sizeof(buf) - 1] = 0; // I'd hope __cxa_demangle does this when the name is huge, but just in case.
return res;
}
The accepted solution [1] works mostly well. I found at least one case (and I wouldn't call it a corner case) where it does not report what I expected... with references.
For those cases, I found another solution, posted at the bottom.
Problematic case (using type
as defined in [1]):
int i = 1;
cout << "Type of " << "i" << " is " << type(i) << endl;
int & ri = i;
cout << "Type of " << "ri" << " is " << type(ri) << endl;
produces
Type of i is int
Type of ri is int
Solution (using type_name<decltype(obj)>()
, see code below):
cout << "Type of " << "i" << " is " << type_name<decltype(i)>() << endl;
cout << "Type of " << "ri" << " is " << type_name<decltype(ri)>() << endl;
produces
Type of i is int
Type of ri is int&
as desired (at least by me)
Code . It has to be in an included header, not in a separately compiled source, due to specialization issues. See undefined reference to template function for instance.
#ifndef _MSC_VER
# include <cxxabi.h>
#endif
#include <memory>
#include <string>
#include <cstdlib>
template <class T>
std::string
type_name()
{
typedef typename std::remove_reference<T>::type TR;
std::unique_ptr<char, void(*)(void*)> own
(
#ifndef _MSC_VER
abi::__cxa_demangle(typeid(TR).name(), nullptr,
nullptr, nullptr),
#else
nullptr,
#endif
std::free
);
std::string r = own != nullptr ? own.get() : typeid(TR).name();
if (std::is_const<TR>::value)
r += " const";
if (std::is_volatile<TR>::value)
r += " volatile";
if (std::is_lvalue_reference<T>::value)
r += "&";
else if (std::is_rvalue_reference<T>::value)
r += "&&";
return r;
}
I've always wanted to use type_info, but I'm sure that the result of the name() member function is non-standard and won't necessarily return anything that can be converted to a meaningful result.
If you are sticking to one compiler, there maybe a compiler specific function that will do what you want. Check the documentation.
참고URL : https://stackoverflow.com/questions/281818/unmangling-the-result-of-stdtype-infoname
'development' 카테고리의 다른 글
VS2012 편집기 탭 색상을 끄는 방법은 무엇입니까? (0) | 2020.09.24 |
---|---|
SQL Server 2008 Management Studio에서 text 또는 varchar (MAX) 열의 전체 내용을 보려면 어떻게합니까? (0) | 2020.09.24 |
ImportError : OS X에서 Python을 업그레이드 한 후 pkg_resources라는 모듈이없는 이유는 무엇입니까? (0) | 2020.09.24 |
$ _SERVER [ 'REMOTE_ADDR']을 신뢰하는 것이 안전합니까? (0) | 2020.09.24 |
루프 중에 TextBox.Text에 추가하면 반복 할 때마다 더 많은 메모리를 차지하는 이유는 무엇입니까? (0) | 2020.09.24 |