zoukankan      html  css  js  c++  java
  • Getbuffer ReleaseBuffer Cstring

      getbuffer是为了让你使用CString类中,保存字符串缓冲区的那块指针.  
      至于releasebuffer,在MSDN中有这样一句话.  
      If   you   use   the   pointer   returned   by   GetBuffer   to   change   the   string   contents,   you   must   call   ReleaseBuffer   before   using   any   other   CString   member   functions.  
      在对GetBuffer返回的指针使用之后需要调用ReleaseBuffer,这样才能使用其他Cstring的operations。否则会发生错误.

     首先举个例子。CString s( "abcd" );
    int len=s.GetLength();
    LPTSTR p = s.GetBuffer( 5 );
    strcpy( p, "Hello" );

    这是 GetBuffer 的第一种用法,也是最简单的一种,不用给它传递参数,它使用默认值 0,意思是:“给我这个字符串的指针,我保证不加长它”。当你调用 ReleaseBuffer 时,字符串的实际长度会被重新计算,然后存入 CString 对象中。

    如果你需要修改 CString 中的内容,它有一个特殊的方法可以使用,那就是 GetBuffer,它的作用是返回一个可写的缓冲指针。

    如果仅仅是读出CString中的内容,那么只需要用GetBuffer(0)即可。如果后面对CString还有其他操作,那么立刻ReleaseBuffer。

    其他:
    GetBuffer() 他会create出所指定大小的空间出来 这个空间是可以让我们修改的
    很多时候 有的 API 会要一个(char*)的指标作为输出
    如果我们就因为这样去产生一个(char*)的buffer 给他 等到资料取出来之後
    便无法使用CString 的种种方便功能
    因此 比较好的做法 便是用GetBuffer()来产生一个buffer空间给他
    等到取出来之後 我们便可以直接使用CString来对他操作
    GetBuffer() 使用完後 最好是呼叫一下ReleaseBuffer()做为结束

    虽然小弟的网志之前已经有很多GetBuffer()的使用了 不过还是附个范例
    CFile file;
    // FILE_NAME 为事先定义好的档案名称
    if(file.Open(FILE_NAME,CFile::modeRead))
    {
    CString szContent;
    int nFileLength = file.GetLength();
    file.Read(szContent.GetBuffer(nFileLength),nFileLength);
    szContent.ReleaseBuffer();
    // 取得档案内容放在szContent中 我们之後可以对其操作
    }

    关于GetBuffer/ReleaseBuffer,网上比较流行的一种说法是:如果你要直接修改CString的内部数据,就要调用GetBuffer/ReleaseBuffer.我也同意这样的表述.

    下面是几个例子,主要是错误的例子,来加深理解.
    1

    CString strTest  =   " 123 " ;
    char *  p  =  strTest.GetBuffer( 0
    );
    int  i  =
     atoi(p);
    strTest.ReleaseBuffer();

    这种用法当然没有错,但是我认为这里的GetBuffer/ReleaseBuffer是没有必要的 ,为什么呢?因为
    int __cdecl atoi(const char *) 的参数是const char*,CString的内部数据肯定不会被修改的
    .
    所以上面的代码可以直接写成

    CString strTest  =   " 123 " ;
    int  i  =  atoi((LPCTSTR)strTest);

    顺 便说一下GetBuffer的参数问题,网上的例子中,很多都是GetBuffer(5) GetBuffer(10)这样的常数,实际中的程序不可能是这么容易事先知道的,所以也就有了 strTest.GetBuffer(strTest.GetLength() )的写法.其实,GetBuffer(0)就可以了.可以由GetBuffer的源码得到验证.

    2

        CString strTest  =   " 123 45 " ;

        
    // some other code

        CString strTest2  =  strTest;//之后两个cstring内容仍然存于同一内存位置
        
    char  seps[]  =   "   "
    ;
        
    char *  pToken  =   0
    ;
        
    // char* pStr = strTest2.GetBuffer(0);

        pToken  =  strtok(( char * )(LPCTSTR)strTest2, seps);
        //pToken  =  strtok(pStr , seps);
        
    while
    (pToken)
            pToken 
    =
     strtok(NULL, seps);
             //strTest2.ReleaseBuffer(0);

    CString   类里面有专门的结构体来记录这些信息  
      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);   }  
      };  
       
      赋值的时候只是简单的把引用计数加1,     nRefs++,然后指向同一内存单元  
      每一个对象销毁时,先把引用计数减1,     nRefs--,然后判断是否为0,如果为0才真正释放  

    运行上面的代码,可以看到strTest的值也变了,呵呵,这就是程序中一些关与CString的奇怪问题的起源.如果用注释中的GetBuffer/ReleaseBuffer方法,就一点问题也没有了.
    同 样,对于ReleaseBuffer的参数,缺省的是-1,但是我不建议.因为-1表示使用当前的00结束符位置来确定新的长度.而上面的例子 中,strtok是会重新设置00结束符的,所以,安全的做法,就是把这个CString的长度设为0,ReleaseBuffer(0),反正它的内容 已经变了,也没有人要用了.
    说明一下,GetBuffer/ReleaseBuffer方法只能保证strTest不变,strTest2还是会变的.所以,对于一个成员变量,比如m_strTest2调用ReleaseBuffer要多一个心眼,局部变量就不用想这么多了.
    那么怎么从最开始就意识到程序写错了呢?上面代码中(char * )(LPCTSTR)是很危险的,把const去掉了,否则strtok是编译不过的,也从一个侧面说明了const的重要性.

  • 相关阅读:
    SQL批量更新
    使用PLSQL导入导出数据库
    Oracle 的Blob使用小结
    基于java的邮件服务器以及webmail的搭建
    Tomcat 系统架构与设计模式 【2】
    修改Oracle XE Listener 占用的1521、8080端口
    nls_lang pl/sql 设置编码
    oracle提高查询效率的解析
    Tomcat 系统架构与设计模式
    hql与sql的区别(转)
  • 原文地址:https://www.cnblogs.com/dongzhiquan/p/1994766.html
Copyright © 2011-2022 走看看