C++中typeID実現原理詳細


最近bootstを見ました。anyのソースコードは主にtypeID操作に依存しています。このように実現する時間と空間の支出がどれぐらいあるか気になります。
VSL 2008に付属するtype_info類はヘッダファイルだけで、ソースファイルがありません。以下のように声明します。

class type_info {
public:
 virtual ~type_info();
 _CRTIMP_PURE bool __CLR_OR_THIS_CALL operator==(const type_info& rhs) const;
 _CRTIMP_PURE bool __CLR_OR_THIS_CALL operator!=(const type_info& rhs) const;
 _CRTIMP_PURE int __CLR_OR_THIS_CALL before(const type_info& rhs) const;
 _CRTIMP_PURE const char* __CLR_OR_THIS_CALL name(__type_info_node* __ptype_info_node = &__type_info_root_node) const;
 _CRTIMP_PURE const char* __CLR_OR_THIS_CALL raw_name() const;
private:
 void *_m_data;
 char _m_d_name[1];
 __CLR_OR_THIS_CALL type_info(const type_info& rhs);
 type_info& __CLR_OR_THIS_CALL operator=(const type_info& rhs);
 _CRTIMP_PURE static const char *__CLRCALL_OR_CDECL _Name_base(const type_info *,__type_info_node* __ptype_info_node);
 _CRTIMP_PURE static void __CLRCALL_OR_CDECL _Type_info_dtor(type_info *);
};
テストコード:

#include <iostream>
using namespace std;
 
class Object
{
};
 
int main()
{
	Object obj;
	cout << "type name:" << typeid(obj).name() << endl;
	cout << "type raw name:" << typeid(obj).raw_name() << endl;
	if(typeid(obj) == typeid(Object))
	{
		cout << "type is equal" << endl;
	}
	else
	{
		cout << "type is not equal" << endl;
	}
	return 0;
}
出力:
type name:class Object
type raw name:AVObject@
type is equal
各関数の実装原理を説明する前に、type(u)を開いてみます。info類の保存方式。
typeIDが戻ってくるのはtype_です。infoの引用は、この類はコピーできないし、自分で作ることもできないので、各クラスは一つのタイプしかないです。infoのデータは、このデータはどこに保管されていますか?
UltraEditでexeファイルを開き、「Object」を検索すると、この文字列が見つかります。このexeをPEツールで開きます。この文字列はdata節に属しています。typeIDがあるコードを全部注釈してください。PEファイルにはこの文字列がありません。結論を出す:
コンパイラは、各タイプのtypeID操作の種類ごとにデータセグメントに保存されたtype_を生成します。infoデータ
このデータの大きさはどれぐらいですか?下のコードを見てください。

#include <iostream>
using namespace std;
 
class Object
{
};
 
int main()
{
	const type_info* p = &typeid(Object);
	cout << p << endl;
	return 0;
}
coutの行のブレークポイントで、pの値が表示されます。

このタイプの声明を見てください。コンストラクタはvirtualタイプですので、pの頭の4バイトは虚関数テーブルです。p+4は_ですm_data、void*タイプ、4バイト、デバッグ時に0が確認されましたが、何を表しているのか分かりません。
p+8は_ですm_d_name、charタイプの配列は、raw_が格納されています。name、各タイプのraw_nameはサイズが一定ではないので、配列長は1です。今タイプinfoの記憶構造は一目瞭然です。
タイプごとのタイプinfoデータ長は、タイプ名に依存し、少なくとも9バイトである。
現在、複雑な工程の中に50種類のタイプがtypeID操作を使っていると仮定します。infoの長さは24で、これらのデータが増加するPEサイズは1200 Bで、1 Kぐらいです。今のPEはややもすれば数十Mですから、これぐらいのスペースの支出は何でもありません。
これらの関数の呼び出しを参照してください。
  • raw_name関数は直接_に戻ります。m_d_nameの住所は、とても早いです。
  • name関数は_を表します。m_d_nameに記憶されている文字列は、実際の名前に復号されても早いです。
  • =操作子は比較的にraw_です。nameが同じかどうかは、とても早いです。
  • 読者は2つの疑問があるかもしれません。
  • が格納されている時、なぜ直接にnameに保存されないですか?一番大きな原因は、省スペース、例えばダブルのraw_です。nameは「.N」で、nameは「double」で4バイト多くなりました。
  • =操作子はどうして直接二つのタイプを比較しないですか?info参照の住所は同じですか?私も戸惑っています。コードを見たら、raw_です。name
  • メモ:C++はtypeidの標準が規定されていません。各コンパイラは異なるかもしれません。上記の分析プロセスはVSL 2008のコンパイラに基づいています。
    まとめ:typeIDによる時間と空間の出費は非常に小さいですが、使う時はなるべく開放閉鎖の原則を守らないようにしてください。
    ここでC++中typeIDの原理を実現する記事を紹介します。C++typeIDの原理を実現するために、以前の文章を検索したり、下記の関連記事を見たりしてください。これからもよろしくお願いします。