C++ 死角Author: 徐艺波(xuyibo) Views: 497 UpdateTime:2007-8-9 |
留言 |
我过去很是不喜欢C++这门语言,当看到有些人评价C++语言差的时候,我总是拍手称快。上个星期重读Steve Lippman《The Inside C++ Object Model》和《ATL开发指南》后,我才打心底下改变了对C++的看法。《The Inside C++ Object Model》里有句话,大体意思就是:“C++适合开发大型软件,但这也是有代价的,开发者需要去了解C++。”,看过去我就是站在C以及排斥C++各种花俏功能(模版、多重继承、虚函数、运算符重载)的角度上,来评价C++的。好了,一句话结束介绍“海纳百川,故成其大”,言归正传。
这篇文章主要是针对介绍VC 2005编译器,介绍C++的死角,一个容易出错、不容易理解、而有每天都会碰到n次的地方。
在VC下,基础数据类型,int、float、double等,delete和delete[]生成的代码一样。但对于删除new分配的数组,用delete[]删除是个好习惯,我不知道Linux和Unix下C++的运行库是如何设计。有知道的,可以回个贴。
VC的C/C++运行库在每次调用new的时候记录了分配数据的大小,new返回的指针是一个_CrtMemBlockHeader数据结构。微软这么设计,估计是可以方便的检查出程序退出后的内存泄漏。为了节省你的时间,和增加印象,我将new和delete的相关代码摘录出来,红色标记的为要害。
/* * For diagnostic purpose, blocks are allocated with extra information and * stored in a doubly-linked list. This makes all blocks registered with * how big they are, when they were allocated, and what they are used for. */ #define nNoMansLandSize 4 typedef struct _CrtMemBlockHeader { struct _CrtMemBlockHeader * pBlockHeaderNext; struct _CrtMemBlockHeader * pBlockHeaderPrev; char * szFileName; int nLine; size_t nDataSize; int nBlockUse; long lRequest; unsigned char gap[nNoMansLandSize]; /* followed by: * unsigned char data[nDataSize]; * unsigned char anotherGap[nNoMansLandSize]; */ } _CrtMemBlockHeader; #define pbData(pblock) ((unsigned char *)((_CrtMemBlockHeader *)pblock + 1)) #define pHdr(pbData) (((_CrtMemBlockHeader *)pbData)-1) void operator delete(void *pUserData) { _CrtMemBlockHeader * pHead; RTCCALLBACK(_RTC_Free_hook, (pUserData, 0)); if (pUserData == NULL) return; _mlock(_HEAP_LOCK); /* block other threads */ __TRY /* get a pointer to memory block header */ pHead = pHdr(pUserData); /* verify block type */ _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)); _free_dbg( pUserData, pHead->nBlockUse ); __FINALLY _munlock(_HEAP_LOCK); /* release other threads */ __END_TRY_FINALLY return; } void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc) { // try to allocate size bytes void *p; while ((p = malloc(size)) == 0) { if (_callnewh(size) == 0) { // report no memory static const std::bad_alloc nomem; _RAISE(nomem); } } return (p); } extern “C” _CRTIMP void * __cdecl malloc(size_t nSize) { void *res = _nh_malloc_dbg(nSize, _newmode, _NORMAL_BLOCK, NULL, 0); RTCCALLBACK(_RTC_Allocate_hook, (res, nSize, 0)); return res; } extern “C” void * __cdecl _heap_alloc_dbg( size_t nSize, int nBlockUse, const char * szFileName, int nLine ) { long lRequest; size_t blockSize; int fIgnore = FALSE; _CrtMemBlockHeader * pHead; void *retval=NULL; /* lock the heap */ _mlock(_HEAP_LOCK); __try { /* verify heap before allocation */ if (check_frequency > 0) if (check_counter == (check_frequency – 1)) { _ASSERTE(_CrtCheckMemory()); check_counter = 0; } else check_counter++; lRequest = _lRequestCurr; /* break into debugger at specific memory allocation */ if (_crtBreakAlloc != –1L && lRequest == _crtBreakAlloc) _CrtDbgBreak(); /* forced failure */ if ((_pfnAllocHook) && !(*_pfnAllocHook)(_HOOK_ALLOC, NULL, nSize, nBlockUse, lRequest, (const unsigned char *)szFileName, nLine)) { if (szFileName) _RPT2(_CRT_WARN, “Client hook allocation failure at file %hs line %d.n”, szFileName, nLine); else _RPT0(_CRT_WARN, “Client hook allocation failure.n”); } else { /* cannot ignore CRT allocations */ if (_BLOCK_TYPE(nBlockUse) != _CRT_BLOCK && !(_crtDbgFlag & _CRTDBG_ALLOC_MEM_DF)) fIgnore = TRUE; /* Diagnostic memory allocation from this point on */ if (nSize > (size_t)(_HEAP_MAXREQ – nNoMansLandSize – sizeof(_CrtMemBlockHeader))) { _RPT1(_CRT_ERROR, “Invalid allocation size: %Iu bytes.n”, nSize); errno = ENOMEM; } else { if (!_BLOCK_TYPE_IS_VALID(nBlockUse)) { _RPT0(_CRT_ERROR, “Error: memory allocation: bad memory block type.n”); } blockSize = sizeof(_CrtMemBlockHeader) + nSize + nNoMansLandSize; #ifndef WINHEAP /* round requested size */ blockSize = _ROUND2(blockSize, _GRANULARITY); #endif /* WINHEAP */ RTCCALLBACK(_RTC_FuncCheckSet_hook,(0)); pHead = (_CrtMemBlockHeader *)_heap_alloc_base(blockSize); if (pHead == NULL) { errno = ENOMEM; RTCCALLBACK(_RTC_FuncCheckSet_hook,(1)); } else { /* commit allocation */ ++_lRequestCurr; if (fIgnore) { pHead->pBlockHeaderNext = NULL; pHead->pBlockHeaderPrev = NULL; pHead->szFileName = NULL; pHead->nLine = IGNORE_LINE; pHead->nDataSize = nSize; pHead->nBlockUse = _IGNORE_BLOCK; pHead->lRequest = IGNORE_REQ; } else { /* keep track of total amount of memory allocated */ _lTotalAlloc += nSize; _lCurAlloc += nSize; if (_lCurAlloc > _lMaxAlloc) _lMaxAlloc = _lCurAlloc; if (_pFirstBlock) _pFirstBlock->pBlockHeaderPrev = pHead; else _pLastBlock = pHead; pHead->pBlockHeaderNext = _pFirstBlock; pHead->pBlockHeaderPrev = NULL; pHead->szFileName = (char *)szFileName; pHead->nLine = nLine; pHead->nDataSize = nSize; pHead->nBlockUse = nBlockUse; pHead->lRequest = lRequest; /* link blocks together */ _pFirstBlock = pHead; } /* fill in gap before and after real block */ memset((void *)pHead->gap, _bNoMansLandFill, nNoMansLandSize); memset((void *)(pbData(pHead) + nSize), _bNoMansLandFill, nNoMansLandSize); /* fill data with silly value (but non-zero) */ memset((void *)pbData(pHead), _bCleanLandFill, nSize); RTCCALLBACK(_RTC_FuncCheckSet_hook,(1)); retval=(void *)pbData(pHead); } } } } __finally { /* unlock the heap */ _munlock(_HEAP_LOCK); } return retval; } __forceinline void * __cdecl _heap_alloc (size_t size) { void *pvReturn; if (_crtheap == 0) { _FF_MSGBANNER(); /* write run-time error banner */ _NMSG_WRITE(_RT_CRT_NOTINIT); /* write message */ __crtExitProcess(255); /* normally _exit(255) */ } if (__active_heap == __SYSTEM_HEAP) { return HeapAlloc(_crtheap, 0, size ? size : 1); } else { if ( __active_heap == __V6_HEAP ) { if (pvReturn = V6_HeapAlloc(size)) { return pvReturn; } } if (size == 0) size = 1; size = (size + BYTES_PER_PARA – 1) & ~(BYTES_PER_PARA – 1); return HeapAlloc(_crtheap, 0, size); } } |
在C++中,将一个指针转换为另一个指针,结果是多少?如果你和我一样,是个C好手,那么你肯定不加思考的说就是这个指针的值。但知道昨天晚上我在次看COM QueryInterface代码的实现,我puzzle了。很显然,结果肯定不是指针本身了,否则QueryInterface也不用这么多if语句来判断了,而且返回的接口肯定会出问题的。
含有多个vptr表格的类,将this指针转换为其中虚函数表类型,VC编译器将根据继承顺序来调整this指针,以返回this指针中相应接口的vptr地址。
Email:[email protected] QQ:85521028 Copyright ©2002-2007 XuYibo All rights reserved. License | Contributor |