当前位置: 首页 > news >正文

网站建设华科技最新seo教程

网站建设华科技,最新seo教程,小型网站如何做,东莞市保安公司MFC里的关于Cstring的类的实现大部分在strcore.cpp中。 Cstring里需要有一个用来存放字符串的缓冲区,并且有一个指针指向该缓冲区,该指针就是LPTSTR m_pchData。但是有些字符串操作会增建或减少字符串的长度,因此为了减少频繁的申请内存或者…

MFC里的关于Cstring的类的实现大部分在strcore.cpp中。

Cstring里需要有一个用来存放字符串的缓冲区,并且有一个指针指向该缓冲区,该指针就是LPTSTR m_pchData。但是有些字符串操作会增建或减少字符串的长度,因此为了减少频繁的申请内存或者释放内存,Cstring会先申请一个大的内存块用来存放字符串。当增加后的字符串长度超过预先申请的内存时,Cstring先释放原先的内存,然后再重新申请一个更大的内存块。同样的,当字符串长度减少时,也不释放多出来的内存空间。而是等到积累到一定程度时,才一次性将多余的内存释放。

    还有,当使用一个Cstring对象a来初始化另一个Cstring对象b时,为了节省空间,新对象b并不分配空间,它所要做的只是将自己的指针指向对象a的那块内存空间,只有当需要修改对象a或者b中的字符串时,才会为新对象b申请内存空间,这叫做写入复制技术(CopyBeforeWrite)。

struct CStringData
{
   long nRefs;             // reference count
   int nDataLength;        // length of data (including terminator)
   int nAllocLength;       // length of allocation
                           // TCHAR data[nAllocLength]

   TCHAR* data()           // TCHAR* to managed data
  { return (TCHAR*)(this+1); }
};

这种结构的数据结构的申请方法是这样实现的:

pData = (CStringData*) new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)];

pData->nAllocLength = nLen;

其中nLen是用于说明需要一次性申请的内存空间的大小的。

    LPTSTR CString::GetBuffer(int nMinBufLength),它的实现方法是:

首先通过Cstring::GetData()取得CstringData对象的指针。该指针是通过存放字符串的指针m_pchData先后偏移sizeof(CstringData),从而得到了CstringData的地址。然后根据参数nMinBufLength给定的值重新实例化一个CstringData对象,使得新的对象里的字符串缓冲长度能够满足nMinBufLength。

然后在重新设置一下新的CstringData中的一些描述值。最后将新CstringData对象里的字符串缓冲直接返回给调用者。

 这些过程用C++代码描述就是:  

    if (nMinBufLength > GetData()->nAllocLength)
    {        
        // we have to grow the buffer        
        CStringData* pOldData = GetData();        

        AllocBuffer(nMinBufLength);        
        memcpy(m_pchData->data(), pOldData->data(), (nOldLen+1)*sizeof(TCHAR));
        
        GetData()->nDataLength = nOldLen;
        
        CString::Release(pOldData);        
    }
    
    return m_pchData;

    很多时候,我们经常的对大批量的字符串进行互相拷贝修改等,Cstring 使用了CopyBeforeWrite技术。

CString::CString(const CString& stringSrc)
{
    m_pchData = stringSrc.m_pchData;
    InterlockedIncrement(&GetData()->nRefs);
}

     这样当修改对象a或对象b的字符串内容时,首先检查CstringData:: nRefs的值。

void CString::CopyBeforeWrite()
{
    if (GetData()->nRefs > 1)
    {
        CStringData* pData = GetData();
        Release();
        AllocBuffer(pData->nDataLength);
        memcpy(m_pchData, pData->data(), (pData- >nDataLength+1)*sizeof(TCHAR));
    }
}

其中Release 就是用来判断该内存的被引用情况的。

void CString::Release()
{
    if (GetData() != _afxDataNil)
    {
        if (InterlockedDecrement(&GetData()->nRefs) <= 0)
            FreeData(GetData());
    }
}

 存在这些问题的operations介绍。

1.      GetBuffer

对于这个operation返回的字符串指针,我们可以直接修改其中的值:

   CString str1("This is the string 1");――――――――――――――――1

   int nOldLen = str1.GetLength();―――――――――――――――――2

   char* pstr1 = str1.GetBuffer( nOldLen );――――――――――――――3

   strcpy( pstr1, "modified" );――――――――――――――――――――4

   int nNewLen = str1.GetLength();―――――――――――――――――5

   原来在对GetBuffer返回的指针使用之后需要调用ReleaseBuffer,这样才能使用其他Cstring的operations。上面的代码中,我们在4-5处增建一行代码:str1.ReleaseBuffer(),然后再观察nNewLen,发现这个时候已经是我们想要的值8了。

GetBuffer返回的是CstringData对象里的字符串缓冲的首地址

ReleaseBuffer源代码中显示的正是我们所猜想的:

   CopyBeforeWrite();  // just in case GetBuffer was not called

    if (nNewLength == -1)

               nNewLength = lstrlen(m_pchData); // zero terminated

    ASSERT(nNewLength <= GetData()->nAllocLength);

   GetData()->nDataLength = nNewLength;

   m_pchData[nNewLength] = '\0';

其中CopyBeforeWrite是实现写拷贝技术的,这里不管它。

    下面的代码就是重新设置CstringData对象中描述字符串长度的那个属性值的。首先取得当前字符串的长度,然后通过GetData()取得CstringData的对象指针,并修改里面的nDataLength成员值。

     但是,现在的问题是,我们虽然知道了错误的原因,知道了当修改了GetBuffer返回的指针所指向的值之后需要调用ReleaseBuffer才能使用Cstring的其他operations时,我们就能避免不在犯这个错误了。答案是否定的。这就像虽然每一个懂一点编程知识的人都知道通过new申请的内存在使用完以后需要通过delete来释放一样,道理虽然很简单,但是,最后实际的结果还是有由于忘记调用delete而出现了内存泄漏。

实际工作中,常常是对GetBuffer返回的值进行了修改,但是最后却忘记调用ReleaseBuffer来释放。而且,由于这个错误不象new和delete人人都知道的并重视的,因此也没有一个检查机制来专门检查,所以最终程序中由于忘记调用ReleaseBuffer而引起的错误被带到了发行版本中。

    要避免这个错误,方法很多。但是最简单也是最有效的就是避免这种用法

比如上面的代码,我们完全可以这样写:

   CString str1("This is the string 1");

   int nOldLen = str1.GetLength();

   str1 = "modified";

   int nNewLen = str1.GetLength();

 但是有时候确实需要,比如:

我们需要将一个Cstring对象中的字符串进行一些转换,这个转换是通过调用一个dll里的函数Translate来完成的,但是要命的是,不知道什么原因,这个函数的参数使用的是char*型的:

DWORD Translate( char* pSrc, char *pDest, int nSrcLen, int nDestLen );

这个时候我们可能就需要这个方法了:

     Cstring strDest;     
     Int nDestLen = 100;     
     DWORD dwRet = Translate( _strSrc.GetBuffer( _strSrc.GetLength() ),     
                              strDest.GetBuffer(nDestLen),     
                              _strSrc.GetLength(), nDestlen );     
     _strSrc.ReleaseBuffer();     
     strDest.ReleaseBuffer();
     
     if ( SUCCESSCALL(dwRet)  )     
     {     
     }     
     if ( FAILEDCALL(dwRet) )     
     {     
     }

    的确,这种情况是存在的,但是,我还是建议尽量避免这种用法,如果确实需要使用,请不要使用一个专门的指针来保存GetBuffer返回的值,因为这样常常会让我们忘记调用ReleaseBuffer。就像上面的代码,我们可以在调用GetBuffer之后马上就调用ReleaseBuffer来调整Cstring对象。

 2.      LPCTSTR

 Cstring类已经将LPCTST重载了。在Cstring中LPCTST实际上已经是一个operation了。对LPCTST的调用实际上和GetBuffer是类似的,直接返回CstringData对象中的字符串缓冲的首地址。

其C++代码实现是:

_AFX_INLINE CString::operator LPCTSTR() const

   { return m_pchData; }

 因此在使用完以后同样需要调用ReleaseBuffer()。

但是,这个谁又能看出来呢?

    其实这个问题的本质原因出在类型转换上。LPCTSTR返回的是一个const char*类型,因此使用这个指针来调用Translate编译是不能通过的。对于一个初学者,或者一个有很长编程经验的人都会再通过强行类型转换将const char*转换为char*。最终造成了Cstring工作不正常,并且这样也很容易造成缓冲溢出。

http://www.hrbkazy.com/news/30395.html

相关文章:

  • 南昌制作网站的公司互联网推广销售
  • wordpress多级筛选seo搜索引擎入门教程
  • 学校网站建设流程百度有人工客服吗
  • 上海发布公众号app优化设计高中
  • 网站做sem对优化有影响吗网络营销ppt
  • 建设网站制百度论坛发帖
  • 南京做网站外包公司怎么做网站推广
  • 钓鱼网站的危害线下推广方式
  • 网站开发工作内容上海谷歌seo推广公司
  • 龙华网站建设谷歌seo排名优化
  • 河南锦路路桥建设有限公司网站网站检测中心
  • 奎屯市网站销售的三个核心点
  • jfinal网站开发模板一个产品的营销方案
  • 免费制作图片的软件有哪些白杨seo教程
  • 贵阳网站建设哪家好方舟优秀营销软文范例800字
  • 能建设传奇私服网站的空间推广平台app
  • 做网站一般费用多少在线crm网站建站
  • 武汉制作网站公司页面seo是什么意思
  • 网站建设联系方式网络推广公司深圳
  • 专业做网站的企业首页排名优化公司
  • 寻找做项目的网站百度云网页版入口
  • 网站平台建设需要注意的是百度推广怎么使用教程
  • 做国外有那些网站比较好的app运营推广策划方案
  • 锦州市做网站韶关新闻最新今日头条
  • 专业的培训行业网站开发百度热搜榜第一
  • 如何直到网站是用什么模板做的广告推广图片
  • 同德县网站建设公司seo优化工具
  • 网站建设个人工作室引擎优化seo怎么做
  • 响应式相册网站模板网站流量排名查询工具
  • 企业网站模板建站流程我在百度下的订单如何查询