真想不到之五:高效字串指针类

原创 2002年03月27日 08:50:00

我的文章可见:
http://www.csdn.net/Author/AdamBear

               真想不到之五:高效字串指针类
关键字:VB、HCAK、字串指针、BSTR、效率、内存共享
难度:中级或高级
参考文章:
1、2000年7月VBPJ Black Belt专栏文章《Modify a Varialbe's Pointer》
   作者:Bill McCarthy
2、1998年4月VBPJ Black Belt专栏文章《Play VB's Strings》
   作者:Francesco Balena

引言:
    本想以内存共享做为VB指针专题的最后一篇,写着写着发现字串的问题应该单独谈谈。在内存共享的问题上,我尤其关心的是字串的共享,因为在我一个多月前发布的源码里用的是《HardCore VB》里Bruce Mckinney提供的CShareStr类,它实现了字串的内存共享。但是Bruce也没有突破局限,对字串的处理依然是CopyMemory的乾坤大挪移,尤其是还要进行讨厌的ANSI/DBCS和Unicode的转换。我在readme里说过它效率极低,应该采用Variant或Byte数组来实现,才能避免转换。后来又想到可以用StrPtr来做,并在VC里用DLL共享节实现了可以不进行转换的字串内存共享。不过在VC里我仍然需要用SysAllocString来建立VB能使用的BSTR。这都不是我想要的,我想要的东西要象VC里的CString的一样,只要字串够大,对其赋值就不用重新分配内存,还要象VC里CComBSTR类一样可以Attach到一个特定BSTR。
    知道该怎么做,是在看了VBPJ上Bill McCarthy和Francesco Balena的两篇文章之后。Bill用修改SafeArray描述结构实现了数组的内存共享,而Francesco则对字串指针进行深入的探讨。但是Bill和Francesco的东西都没有实现我想要的字串类。
    方法知道了,实现并不难,所以我决定自己来包装一个这样的东西。
       


正文:
    使用VB里的字串类型String有两大不足:第一、它的分配是由VB运行时控制,我们不能将其分配在指定内存处;第二,任何一次对字串的赋值操作都要进行内存重新分配。要实现高效、灵活的字串处理,我们必须克服这两大不足。
    对于第一个问题,通过修改String变量里放着的BSTR描述符指针可以实现;对于第二个问题,可以用Mid语句(注意是语句而不是函数)来赋值。不详细讲了,直接看下面的这个类:

    Option Explicit
   
    '********************************************************
    'clsBSTR.cls
    '作者: 熊超         ID: AdamBear        2002年3月18日
    'http://www.csdn.net/Author/AdamBear
    '    你可以自由使用本类模块,不过请保留本声明
    '********************************************************
   
    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
   
    '不要直接对sString赋值(可以用MID语句),将其设为公有仅为提高效率。
    Public sString As String                'BSTR描述符指针
   
    Private pStr As Long                    'BSTR地址
    Private nMaxLen As Long                 'BSTR最大字节数
   
   
   
    '让本字串指向特定地址
    Public Sub Attach(Addr As Long, Optional nLen As Long)
        pStr = Addr
        '修改BSTR描述符指针,使其指向Addr
        CopyMemory ByVal VarPtr(sString), Addr, 4
       
        If IsMissing(nLen) Then Exit Sub
        '设定最大字串字节数
        nMaxLen = nLen
       
    End Sub
   
    '还原本字串原BSTR描述符
    Public Sub Detach()
        CopyMemory ByVal VarPtr(sString), 0&, 4
    End Sub
   
    '让本字串指向源字串
    Public Sub AttachStr(sStr As String)
        Attach StrPtr(sStr), LenB(sStr)
    End Sub
   
    'data为缺省属性
    Public Property Let data(sVal As String)
        Dim c As Long
        c = LenB(sVal)
 '超过最大字串数,抛出错误。
        If c > nMaxLen Then Err.Raise vbObjectError + 3000, _
                                  "CString::Let Data", "溢出"
        '写字串长度
        CopyMemory ByVal (pStr - 4), c, 4
        '写字串
        Mid(sString, 1) = sVal
    End Property
   
    '可以通过公有变量sString来读字串,效率更高
    Public Property Get data() As String
        data = sString
    End Property

    Private Sub Class_Terminate()
        Call Detach
    End Sub
   
    用法如下,假设我们已通过VitualAlloc,HeapAlloc,MapViewOfFile这样的内存管理API得到了一个4k个字节的可读写的内存地址baseAddr:
    Dim sShare As New clsBSTR
    '留下前4个字节用于BSTR保存字串字节数
    sShare.Attach(baseAddr+4, 4096-4)
    '下面的字串"Test"会直接写到baseAddr+4字节处
    sShare = "Test"   
    Dim y As String
    '读字串时可以用sString属性或缺省属性
    y = sShare.sString
    '用AttachStr方法Attach到一个字串。
    '必须要先Detach
    sShare.Detach
    sShare.AttachStr(y)
    sShare = "Hahaha"
    Debug.Print y
    '一旦AttachStr到字串y后,对sShare的修改就相当于对y的修改。
    '并且以后对y的修改也只能用Mid语句
    Mid(y, 1) = "xxxxx"
    '不能直接赋值,这样VB会将原来y所指(也是sShare所指)内存释放,
    '    重新分配y。这样在访问sShare时会出错。
    'y = "Test"
       
   
    我也不在这里讲这个类的详细原理,可以参考我前面说的两篇文章。
    使用这个类有几个需要注意的地方。
    1、读字串时可以用sString属性来读,更快。 
    读sShare有两种方法,一种是用缺省属性Data来读,一种是直接用sString属性来读。用sString属性不重新分配内存,要快得多。
    2、不要直接给sString赋值,应使用缺省的data属性来赋值。
    之所以把sString属性暴露出来,是为了效率和方便。我们可以用Mid语句对其进行修改,但不要直接用"="来赋值。
    3、注意Attach的第二个参数,表示字串的最大字节数,不要让它超过已经分配的内存。
    4、用AttachStr将本字串对象Attach到某个字串(比如上面的y)上后,不能再对这个字串y重新赋值,也不能将其传递到会对其重新赋值的过程。
      
    哇,这么多需要注意的问题,用起来岂不是更不方便。的确,用它的之前要考虑是不是必须的。因为建立这个类也一样有开销。所以还有一个需要注意的问题:

    5、它主要的应用还是在于将字串安放在指定内存处。虽然它也可以让同一个进程内几个的字串达到共享的目的,但是如果只是两三个很小的字串这样时做反而慢了。
   

后计:
    数组指针和字串指针我们已经谈过了,对于普通的数值类型变量的指针没有什么Hack的必要,但是它关系到一个有用的技术,下篇文章再谈。
    本文和下篇文章的代码,以及用这个类来实现的共享内存的代码,我会发布到CSDN共享软件上,名字是《内存共享和指针》。

版权声明:本文为博主原创文章,未经博主允许不得转载。

指针相减(同类型与不同类型)

前言:本文是转载的,但由于转载地址仍然是转载的,所以不知原文出处,对此表示抱歉,但仍对原作者表示深深的敬意!!!谢谢!!      如果两个指针指向同一个数组,它们就可以相减,其结果为两个指针之...
  • harvic880925
  • harvic880925
  • 2013年05月21日 09:59
  • 8182

指针做形参,形参的传递详解

一、用二级指针作为函数参数,有两种典型情况: 1.需要传递一级指针的数组时: 例如标准C的main函数: int main(int argc, char*[] argv),数组最高维可以退化,c...
  • u011042188
  • u011042188
  • 2015年06月16日 18:55
  • 1532

js处理小数 , toFixed()的潜在问题

一、toFixed能做什么? 以下是摘自网络的toFixed的介绍: toFixed 方法: 返回一个字符串,代表一个以定点表示法表示的数字。 numObj.toFixed([fractionD...
  • zhouchao001
  • zhouchao001
  • 2015年12月13日 17:37
  • 9370

通过操作指针,与指针做函数参数'实现字串在主串中出现的次数,然后将出现的部分按照要求进行替换

通过操作指针,与指针做函数参数'实现字串在主串中出现的次数,然后将出现的部分按照要求进行替换...
  • han1558249222
  • han1558249222
  • 2014年05月13日 22:24
  • 907

ehcache 集群使用 rmi方式 有图有真想

ehcache rmi方式 局域网内集群
  • xh199110
  • xh199110
  • 2014年08月11日 08:57
  • 3324

天文爱好者福利:掀开裙纸看真想之动手制造一个黑洞

                          编码之妙 2016-09-10 16:08 理论上来说,任何有质量的物质,只...
  • sinat_35801282
  • sinat_35801282
  • 2016年09月10日 16:24
  • 272

无限风光在险峰:你真想创业?

编者按: 本文作者Mark Suster曾两次创业,现为VC。第二次创业把公司卖给Salesforce,并成为产品管理副总。后加入GRP合伙人投资公司,专注于早期科技公司投资。  第一次见我的创业者总...
  • jasova
  • jasova
  • 2011年02月15日 20:57
  • 2577

真想学习?扔掉你详细的计划吧

原文:http://zhichang.umiwi.com/2011/0809/27667.shtml 该不该定个计划?详细的计划确实可以更高效,也许可以将你减肥的速度加快一倍。但是如果想学习,还是扔...
  • xiexiaofei_ll
  • xiexiaofei_ll
  • 2011年12月19日 10:08
  • 536

win7当wifi热点,解决一根网线,多台笔记本上网(有图有真想)

首先,利用记事本写三句命令   1、netsh wlan set hostednetwork mode=allow    然后另存为或重名为后缀名为.bat的文件   2、netsh wlan...
  • wxlhlh001
  • wxlhlh001
  • 2012年03月07日 10:58
  • 1203

世界上没有绝对的真想,只要努力就能够扭转局势

全民目击这部电影看的太爽了,这是纯粹的演技与故事情节的结合的大片,一件简单的事情,从不同的角度出发又会有不同的看法,会有不同的结果,无知少女撞死了人,并且有物证与人证,后来巧妙嫁接到司机身上,最后又巧...
  • wyxhd2008
  • wyxhd2008
  • 2013年12月21日 00:01
  • 549
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:真想不到之五:高效字串指针类
举报原因:
原因补充:

(最多只允许输入30个字)