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

ppt软件下载免费版百度自然排名优化

ppt软件下载免费版,百度自然排名优化,怎么帮人做网站,wordpress网站渗透测试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.hkea.cn/news/912940/

相关文章:

  • 小规模纳税人企业所得税怎么征收广州seo招聘
  • 济南企业自助建站网络营销策划公司
  • iis 新建网站 要登录温州seo推广外包
  • 个人想做企业网站备案惠州seo代理商
  • 做公务员题的网站口红的推广软文
  • 福州网站建设 联系yanktcn 04上海百网优seo优化公司
  • 网站备案号如何获得网站建设营销推广
  • 物流网站开发公司西安 做网站
  • 商务信息网站怎么做网络视频营销策略有哪些
  • 社交做的最好的网站怎么开发一个网站
  • 教育品牌网站建设百度搜索推广和信息流推广
  • 虎门专业做网站对网络营销的认识有哪些
  • 投资理财培训网站建设抖音引流推广一个30元
  • 做景观设施的网站网络营销推广要求
  • 携程网站建设进度及实施过程网络营销的缺点及建议
  • 石家庄网站建设哪家专业中国联通腾讯
  • 能访问各种网站的浏览器百度一下网页搜索
  • 自己做网站花多少钱雅虎搜索
  • 哈尔滨招标信息网网站推广优化排名教程
  • 个人可以建论坛网站吗福清网络营销
  • 济南做网站优化价格百度推广网站一年多少钱
  • 做网上商城网站哪家好杭州seo靠谱
  • 做营销网站制作关键词优化课程
  • 网站移动终端建设口碑营销成功案例
  • 美国做试管婴儿 网站推广普通话宣传语
  • 网站备案信息查询系统软文发布平台媒体
  • 泊头哪给做网站的好制作网页的教程
  • 漳州建设银行网站首页在百度上打广告找谁
  • 网站免费建站k网络营销策划方案书
  • 网站建设类公网店推广的作用