zoukankan      html  css  js  c++  java
  • VC5.0中的ATL的一个有趣的bug

    从VC5.0开始,ATL正式作为VC的一部分开始发布,可能M$对它的成熟度已经很自信。在阅读这个版本的ATL的源码时,ATLWIN.cpp中有如下代码:
    BOOL CDynamicChain::SetChainEntry(DWORD dwChainID, CMessageMap* pObject, DWORD dwMsgMapID /* = 0 */)
    {
    // first search for an existing entry

        for(int i = 0; i < m_nEntries; i++)
        {
            if(m_pChainEntry[i] != NULL && m_pChainEntry[i]->m_dwChainID == dwChainID)
            {
                m_pChainEntry[i]->m_pObject = pObject;
                m_pChainEntry[i]->m_dwMsgMapID = dwMsgMapID;
                return TRUE;
            }
        }

    // create a new one

        ATL_CHAIN_ENTRY* pEntry = NULL;
        ATLTRY(pEntry = new ATL_CHAIN_ENTRY);

        if(pEntry == NULL)
            return FALSE;

    // search for an empty one

        for(i = 0; i < m_nEntries; i++)
        {
            if(m_pChainEntry[i] == NULL)
            {
                m_pChainEntry[i] = pEntry;  //注意此处,pEntry还没有被赋值,就加入m_pChainEntry中,是一个明显的bug
                return TRUE;
            }
        }

    // add a new one

        ATL_CHAIN_ENTRY** ppNew = NULL;
        ATLTRY(ppNew = new ATL_CHAIN_ENTRY*[m_nEntries + 1]);

        if(ppNew == NULL)
        {
            delete pEntry;
            return FALSE;
        }

        pEntry->m_dwChainID = dwChainID;
        pEntry->m_pObject = pObject;
        pEntry->m_dwMsgMapID = dwMsgMapID;

        if(m_pChainEntry != NULL)
        {
            memcpy(ppNew, m_pChainEntry, m_nEntries * sizeof(ATL_CHAIN_ENTRY*));
            delete [] m_pChainEntry;
        }

        m_pChainEntry = ppNew;

        m_pChainEntry[m_nEntries] = pEntry;

        m_nEntries++;

        return TRUE;
    }
        CDynamicChain::SetChainEntry具有初始化m_pChainEntry并向其中添加元素的功能,上面在数组 m_pChainEntry中添加值的时候,pEntry明显还没有被赋值,所以在此处执行return语句,肯定时不正确的,所以应该把"add a new one"代码段的为pEntry赋值的语句提前。
        另外,在"add a new one"代码段中添加一个新的元素时,数组每次只扩冲一个元素大小,效率肯定很低。如果考虑空间和时间的折中,至少也应该扩充0.75大小的空间。
        我修改后的代码如下:
        BOOL CDynamicChain::SetChainEntry(DWORD dwChainID, CMessageMap* pObject, DWORD dwMsgMapID /* = 0 */)
    {
    // first search for an existing entry

        for(int i = 0; i < m_nEntries; i++)
        {
            if(m_pChainEntry[i] != NULL && m_pChainEntry[i]->m_dwChainID == dwChainID)
            {
                m_pChainEntry[i]->m_pObject = pObject;
                m_pChainEntry[i]->m_dwMsgMapID = dwMsgMapID;
                return TRUE;
            }
        }

    // create a new one

        ATL_CHAIN_ENTRY* pEntry = NULL;
        ATLTRY(pEntry = new ATL_CHAIN_ENTRY);

        if(pEntry == NULL)
            return FALSE;

        pEntry->m_dwChainID = dwChainID;
        pEntry->m_pObject = pObject;
        pEntry->m_dwMsgMapID = dwMsgMapID;
    // search for an empty one

        for(i = 0; i < m_nEntries; i++)
        {
            if(m_pChainEntry[i] == NULL)
            {
                m_pChainEntry[i] = pEntry;  //注意此处,pEntry还没有被赋值,就加入m_pChainEntry中,是一个明显的bug
                return TRUE;
            }
        }

    // add a new one

        ATL_CHAIN_ENTRY** ppNew = NULL;
            int nNewSize = (int)((float)m_nEntries * 1.75f);
        ATLTRY(ppNew = new ATL_CHAIN_ENTRY*[nNewSize]);

        if(ppNew == NULL)
        {
            delete pEntry;
            return FALSE;
        }
            memset((void*)ppNew, NULL, sizeof(ATL_CHAIN_ENTRY) * nNewSize);
        if(m_pChainEntry != NULL)
        {
            memcpy(ppNew, m_pChainEntry, m_nEntries * sizeof(ATL_CHAIN_ENTRY*));
            delete [] m_pChainEntry;
        }

        m_pChainEntry = ppNew;

        m_pChainEntry[m_nEntries] = pEntry;

        m_nEntries = nNewSize

        return TRUE;
    }   
        下面给出VC6.0的AfxWin.h中这个函数的代码:
    BOOL SetChainEntry(DWORD dwChainID, CMessageMap* pObject, DWORD dwMsgMapID = 0)
    {
        // first search for an existing entry

            for(int i = 0; i < m_aChainEntry.GetSize(); i++)
            {
                if(m_aChainEntry[i] != NULL && m_aChainEntry[i]->m_dwChainID == dwChainID)
                {
                    m_aChainEntry[i]->m_pObject = pObject;
                    m_aChainEntry[i]->m_dwMsgMapID = dwMsgMapID;
                    return TRUE;
                }
            }

        // create a new one

            ATL_CHAIN_ENTRY* pEntry = NULL;
            ATLTRY(pEntry = new ATL_CHAIN_ENTRY);

            if(pEntry == NULL)
                return FALSE;

            pEntry->m_dwChainID = dwChainID;
            pEntry->m_pObject = pObject;
            pEntry->m_dwMsgMapID = dwMsgMapID;

        // search for an empty one

            for(i = 0; i < m_aChainEntry.GetSize(); i++)
            {
                if(m_aChainEntry[i] == NULL)
                {
                    m_aChainEntry[i] = pEntry;
                    return TRUE;
                }
            }

        // add a new one

            BOOL bRet = m_aChainEntry.Add(pEntry);

            if(!bRet)
            {
                delete pEntry;
                return FALSE;
            }

            return TRUE;
    }
    上面可以看出VC6.0中这个bug已经去除,而且数组改用m_aChainEntry(类型为CSimpleArray),是个包装后的数组,效果应该比上面的好多。
  • 相关阅读:
    使用 kill 命令杀死 java进程,你用对了吗?
    脚本 启动/停止 jar包服务
    Zipkin和微服务链路跟踪
    nacos初探--作为配置中心
    第一次有人把“分布式事务”讲的这么简单明了
    SquishIt引起的HTTP Error 500.0
    imagesLoaded – 检测网页中的图片是否加载
    25个精美的创意机构和设计工作室网站案例
    使用 FocusPoint.js 实现图片的响应式裁剪
    设计师收藏的20款英文手写字体【免费下载】
  • 原文地址:https://www.cnblogs.com/menggucaoyuan/p/2079326.html
Copyright © 2011-2022 走看看