C++学习笔记

    From: xuyibo.net  Updated: 2007-10-31

    邮件通知当更新时自动发送邮件通知。
    评论本文有什么建议或评论,可以贴一下。
    我要捐助你的支持,让我们做的更好。

  1. 介绍
  2. 我过去很是不喜欢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次的地方。

  3. 对于基础数据类型,delete和delete[]生成代码一样
  4. 在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);

        }
    }

  5. 类型转换
  6. 在C++中,将一个指针转换为另一个指针,结果是多少?如果你和我一样,是个C好手,那么你肯定不加思考的说就是这个指针的值。但知道昨天晚上我在次看COM QueryInterface代码的实现,我puzzle了。很显然,结果肯定不是指针本身了,否则QueryInterface也不用这么多if语句来判断了,而且返回的接口肯定会出问题的。

    含有多个vptr表格的类,将this指针转换为其中虚函数表类型,VC编译器将根据继承顺序来调整this指针,以返回this指针中相应接口的vptr地址。

  7. 相关文章
  8. 部署你的自动构建
    cl.exe 的/Gm参数
    VC++ Minimum Rebuild Dependency File
    VC2003/VC2008编译器性能
    Visual C++生成调试信息(转)
    VC2005编译器堆栈检查汇编码
    国产文件编辑器 - FlexEdit

  9. 评论本文:
  10. EMail: