1. ホーム
  2. c++

[解決済み] std::type_info::name の結果のアンマッチング

2022-05-17 19:25:19

質問

私は現在、特に呼び出し関数に関する情報を表示することになっている、いくつかのロギングコードに取り組んでいます。これは比較的簡単なはずで、標準の C++ には type_info クラスがあります。これはtypeidされたクラス/関数/その他の名前を含んでいますが、それは混乱したものです。あまり有用ではありません。すなわち typeid(std::vector<int>).name() は返す St6vectorIiSaIiEE .

ここから何か有用なものを生み出す方法はないのでしょうか?例えば std::vector<int> のように。もし、テンプレート以外のクラスでしか機能しないのであれば、それも結構です。

解決策はgccでも動くはずですが、移植できればもっといいんですけどね。ロギング用なので、オフにできないほど重要ではありませんが、デバッグには役立つはずです。

解決方法は?

この質問/回答が注目されていること、また、以下のような貴重なフィードバックがあることを考えると GManNickG からの貴重なフィードバックもあり、私はコードを少し整理しました。C++11の機能を備えたバージョンと、C++98の機能のみを備えたバージョンの2つを用意しました。

ファイル中の 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 64bitとg++ 4.7.2 (Mingw32, Win32 XP SP2)で、g++ 4.9.0 20140302 (experimental), clang++ 3.4 (trunk 184647), clang 3.5 (trunk 202594) でテストしています。

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 docより)。 もし output_buffer が十分な長さでない場合、それを展開するために realloc ." 呼び出し realloc() をスタックへのポインタで呼び出す ...痛い! (参照 イゴール スコチンスキー の親切なコメントもご覧ください)。

これらのバグは簡単に確認することができます。 ではなく 15 よりも長い名前 (つまり realloc() ではなく は呼び出されない)。それでも、システムやコンパイラの最適化によっては、出力は「ゴミ」「何もない」「プログラムのクラッシュ」となります。

2つ目のバグを検証するために:バッファサイズを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;
}