C++中typeid實(shí)現(xiàn)原理詳解
最近看了boost::any類源碼,其實(shí)現(xiàn)主要依賴typeid操作符。很好奇這樣實(shí)現(xiàn)的時(shí)間和空間開銷有多大,決定探一下究竟。
VS2008附帶的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
在解釋每個(gè)函數(shù)的實(shí)現(xiàn)原理前先開看type_info類的存儲(chǔ)方式。
typeid返回的是type_info的引用,這個(gè)類不能拷貝,也不能自己構(gòu)造,所以每個(gè)類最多只有一個(gè)type_info的數(shù)據(jù),這個(gè)數(shù)據(jù)存放在哪里的呢?
用UltraEdit打開exe文件,搜索“Object”,能找到這個(gè)字符串。再用PE工具打開這個(gè)exe,發(fā)現(xiàn)這個(gè)字符串屬于data節(jié)(這是可讀可寫的全局?jǐn)?shù)據(jù)段)。再把有typeid的代碼都注釋,PE文件中沒有了這個(gè)字符串。得出一個(gè)結(jié)論:
編譯器會(huì)為每一種typeid操作的類型生成一份保存在數(shù)據(jù)段的type_info數(shù)據(jù)。
這份數(shù)據(jù)有多大呢?看下面這段代碼:
#include <iostream>
using namespace std;
class Object
{
};
int main()
{
const type_info* p = &typeid(Object);
cout << p << endl;
return 0;
}
在cout那一行下斷點(diǎn),查看到p的值為:

再看下這個(gè)類的聲明,析構(gòu)函數(shù)為virtual類型的,所以p的頭四字節(jié)為虛函數(shù)表。p+4為_m_data,void*類型,四個(gè)字節(jié),調(diào)試時(shí)發(fā)現(xiàn)都是0,還不清楚其表示什么。
p+8為_m_d_name,char類型數(shù)組,存儲(chǔ)的是raw_name,每種類型的raw_name大小不定長,所以數(shù)組長度為1?,F(xiàn)在type_info的存儲(chǔ)結(jié)構(gòu)已經(jīng)一目了然:
每種類型的type_info數(shù)據(jù)長度依賴于類型名稱,至少9個(gè)字節(jié)。
現(xiàn)在假設(shè)一個(gè)復(fù)雜的工程里面有50個(gè)類型用了typeid操作符,平均每個(gè)type_info長度為24,這些數(shù)據(jù)增加的PE大小為1200B,就1K左右。而現(xiàn)在的PE動(dòng)輒幾十M,所以這點(diǎn)空間開銷根本不算什么。
再看看這些函數(shù)調(diào)用的開銷:
- raw_name函數(shù)直接返回_m_d_name的地址,非???;
- name函數(shù)將_m_d_name存儲(chǔ)的字符串解碼成實(shí)際的名稱,也是很快;
- ==操作符是比較raw_name是否相等,也是很快。
讀者可能會(huì)有兩點(diǎn)疑惑:
- 存儲(chǔ)的時(shí)候?yàn)槭裁床恢苯哟鎯?chǔ)成name呢?我想最大的原因是節(jié)省空間,比如double的raw_name為".N",name為"double"多了四字節(jié)。
- ==操作符為什么不直接比較兩個(gè)type_info引用的地址是否相等呢?我也很疑惑,我看匯編碼發(fā)現(xiàn)它是比較raw_name。
備注:C++并沒有規(guī)定typeid實(shí)現(xiàn)標(biāo)準(zhǔn),各個(gè)編譯器可能會(huì)不一樣,上述分析過程基于VS2008自帶的編譯器。
總結(jié):typeid帶來的時(shí)間和空間開銷是非常小的,不過使用的時(shí)候盡量不要違背開放封閉原則。
到此這篇關(guān)于C++中typeid實(shí)現(xiàn)原理的文章就介紹到這了,更多相關(guān)C++ typeid實(shí)現(xiàn)原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言學(xué)生成績管理系統(tǒng)課程設(shè)計(jì)word版
這篇文章主要為大家詳細(xì)介紹了C語言學(xué)生成績管理課程設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12
詳解C++中vector的理解以及模擬實(shí)現(xiàn)
vector是表示可變大小數(shù)組的序列容器。這篇文章主要為大家詳細(xì)介紹了vector的理解以及模擬實(shí)現(xiàn),文中的示例代碼講解詳細(xì),感興趣的可以了解一下2023-03-03
C語言關(guān)鍵字const和指針的結(jié)合使用
這篇文章主要介紹了C語言關(guān)鍵字const和指針的結(jié)合,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02

