深入分析深入分析:C++模板究竟会使代码膨胀吗模板究竟会使代码膨胀吗
今天和同事说到C++模板会使代码膨胀, 可同事觉得不会。同事的依据是: 如果模板会使代码膨胀, 那么ATL和WTL里为什么还要大量
使用模板? 同样功能 ,ATL和WTL编译出的可执行文件可比MFC编译的要小的多
今天和同事说到C++模板会使代码膨胀, 可同事觉得不会。
同事的依据是: 如果模板会使代码膨胀, 那么ATL和WTL里为什么还要大量使用模板? 同样功能 ,ATL和WTL编译出的可执行文件可比MFC编译的要小
的多。
我当时一愣 ,事实确实如同事所说,难道模板会使代码膨胀的观点是错误的吗?
MFC因为本身代码量和复杂性在那里, 所以它生成比较大的exe无可厚非。我们这里重点关注为什么ATL/WTL使用模板,但是却不会使生成的exe变
大。
我们知道使用模板时, 同一模板生成不同的模板实类后会是多份代码 ,比如 vector<int>, vector<char>, vector<double>, 这里总共会生成3份不同的
vector代码,这就是我们平时所说的代码膨胀。
那么为什么ATL/WTL就没有代码膨胀的问题呢?
我这里以 ATL里的窗口代码为例来分析这个问题,因为我对WinDbg比较熟悉,下面我会以WinDbg为工具来分析我以前的写得那个俄罗斯方块程序。
首先我们看一下首先我们看一下ATL的窗口代码的窗口代码:
复制代码 代码如下:
template <class T, class TBase /* = CWindow */, class TWinTraits /* = CControlWinTraits */>
class ATL_NO_VTABLE CWindowImpl : public CWindowImplBaseT< TBase, TWinTraits >
{
public:
DECLARE_WND_CLASS(NULL)
static LPCTSTR GetWndCaption()
{
return NULL;
}
HWND Create(HWND hWndParent, _U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
DWORD dwStyle = 0, DWORD dwExStyle = 0,
_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
{
if (T::GetWndClassInfo().m_lpszOrigName == NULL)
T::GetWndClassInfo().m_lpszOrigName = GetWndClassName();
ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);
dwStyle = T::GetWndStyle(dwStyle);
dwExStyle = T::GetWndExStyle(dwExStyle);
// set caption
if (szWindowName == NULL)
szWindowName = T::GetWndCaption();
return CWindowImplBaseT< TBase, TWinTraits >::Create(hWndParent, rect, szWindowName,
dwStyle, dwExStyle, MenuOrID, atom, lpCreateParam);
}
};
上面是一个模板类,它应该会生成多份模板实例代码:我们可以用WinDbg的符号搜索命令来做验证:
输入 x HYTeris!ATL::CWindowImpl<* , 搜索所有以 HYTeris!ATL::CWindowImpl< 开头的符号
复制代码 代码如下:
0:000> x HYTeris!ATL::CWindowImpl<*
004592f0 HYTeris!ATL::CWindowImpl<CTsButton,WTL::CButtonT<ATL::CWindow>,ATL::CWinTraits<1442840576,0> >::Create (struct HWND__ *,
class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
004343a0 HYTeris!ATL::CWindowImpl<CTsMainStatusPane,ATL::CWindow,ATL::CWinTraits<1442840576,0>
>::~CWindowImpl<CTsMainStatusPane,ATL::CWindow,ATL::CWinTraits<1442840576,0> > (void)
00437c90 HYTeris!ATL::CWindowImpl<CTsMainControlPane,ATL::CWindow,ATL::CWinTraits<1442840576,0> >::GetWndCaption (void)
00430440 HYTeris!ATL::CWindowImpl<CTsGameMainWnd,ATL::CWindow,ATL::CWinTraits<114229248,262400>
>::CWindowImpl<CTsGameMainWnd,ATL::CWindow,ATL::CWinTraits<114229248,262400> > (void)
0041c990 HYTeris!ATL::CWindowImpl<CTsAgentWindow,ATL::CWindow,ATL::CWinTraits<1442840576,0> >::GetWndCaption (void)
0044cf50 HYTeris!ATL::CWindowImpl<CTsNextElementContainer,ATL::CWindow,ATL::CWinTraits<1442840576,0>
>::~CWindowImpl<CTsNextElementContainer,ATL::CWindow,ATL::CWinTraits<1442840576,0> > (void)
004539a0 HYTeris!ATL::CWindowImpl<CTsMutiScoreContainer,ATL::CWindow,ATL::CWinTraits<1442840576,0> >::Create (struct HWND__ *,
class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
00435800 HYTeris!ATL::CWindowImpl<CTsGameMainWnd,ATL::CWindow,ATL::CWinTraits<114229248,262400> >::Create (struct HWND__ *,
class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
00434640 HYTeris!ATL::CWindowImpl<CTsKeyEdit,WTL::CEditT<ATL::CWindow>,ATL::CWinTraits<1442840576,0>
>::~CWindowImpl<CTsKeyEdit,WTL::CEditT<ATL::CWindow>,ATL::CWinTraits<1442840576,0> > (void)
00437440 HYTeris!ATL::CWindowImpl<CTsGameMainWnd,ATL::CWindow,ATL::CWinTraits<114229248,262400> >::GetWndCaption (void)
00436020 HYTeris!ATL::CWindowImpl<CTsMainButtonPane,ATL::CWindow,ATL::CWinTraits<1442840576,0> >::Create (struct HWND__ *, class
ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
00453f70 HYTeris!ATL::CWindowImpl<CTsNextElementContainer,ATL::CWindow,ATL::CWinTraits<1442840576,0> >::GetWndCaption (void)
00424e30 HYTeris!ATL::CWindowImpl<CTsDisplayContainer,ATL::CWindow,ATL::CWinTraits<1442840576,0>
>::~CWindowImpl<CTsDisplayContainer,ATL::CWindow,ATL::CWinTraits<1442840576,0> > (void)