基于堆栈上的字符串实现

基于堆栈上的字符串实现

           C++中,由于字符串一开始并非内置的类型,于是,史前时代,江湖上出现了种种的字符串,各有各的优点,但自然,也各有各的缺陷,群雄割据,天下大乱,民不聊生。大伙儿盼星星,盼月亮,盼着真正的字符串能出来一统江湖,好不容易,等到1998C++标准出来了,官方的字符串string终于露面了,自然,它并不是语言内置支持的,而是在STL库中。当然,字符串这东西,就算要在C++编译器的层面上给予支持,其实也很不容易。可是,这个官方的string,单纯它复杂的模板定义和那一大陀函数成员,就足以吓退众多意志不坚定之人。好了,好不容易,鼓起勇气,再仔细瞅瞅string中的东西,发现它也不是很美妙,既不强大,部分函数的功能存在重复又或者STL的算法中已有提供,更要命的是,效率也不怎么高。总之,不能说string的设计不如史前的各种stringS,但也强不到那里去。当然,官方的总比非官方的更具权威,但每次使用string时,想到它背地里除了正常字符串操作之外,还可能做了各种的低效的内存分配释放的操作,又或者线程安全,又或者引用计数,内心就一直惴惴不安。于是,宁愿一再小心翼翼地用着字符数组。但是,用得多了,也很郁闷,字符数组自然高效、灵活,但总是要千编一律地一再写着容易出错的代码,我脆弱的心灵终于头晕眼花了。于是,我决定按照自己的意愿写一个字符串,不敢欲与群雄争锋,只是,为了能够在自己的代码中,替换字符数组。我对它的要求是,字符数组能做到的事情,它也要做到,并且,效率上,绝不妥协。

          俗话说,过早的优化是万恶之源。但在此,在设计本家字符串时,一开始,就要考虑到效率的细节上去了。首先,它要支持堆栈变量的形式,不要它进行内存的分配释放操作,就好像堆栈上的字符数组那样。咦,好像很神奇,其实,只要想到TR1中那个经典的array,通过使用神奇的模板技术,就有办法做到了。所以,此字符串的使用好比这样子,CStackString <MAX_PATH> sFile,暂时假定这个字符串的名字叫CStackString

          但是,使用模板之后,字符串的字符数组的长度只要不一样,它们就都属于不同类型变量,并且之间还都不兼容呢,虽然它们都是字符串。此外,还会编译器还将生产出一堆重复的代码。这无论如何,都不能忍受。于是,自然而然,就想到了继承。CStackString模板类继承于非模板的mybasestringmybasestring中实现了CStackString的各种各样的操作,而CStackString只要仿照array那样子,定义好自己的数据成员即可。嗯,还是看看代码,马上就明白到底是怎么一回事了。


class  CMyBaseString
{
public:
    typedef size_t size_type;
    typedef 
char *pointer;
    typedef 
const char *const_pointer;
    typedef CMyBaseString _Myt;

public:
    
char operator[](size_type nPos)const
    
{
        assert(nPos 
< m_nLen);
        
return m_str[nPos];
    }


    const_pointer c_str()
const return m_str; }

    const_pointer right(size_type nLen)
const
    
{
        assert(nLen 
< m_nLen);
        
return m_str+m_nLen-nLen;
    }


    
int compare(const_pointer str)const
    
{
        
return strcmp(m_str, str);
    }


    _Myt
& assign(const char* str)
    
{
        m_nLen 
= strlen(str);
        assert(m_nLen 
< m_nBuffSize);
        strcpy(m_str, str);
        
return *this;
    }


    _Myt
& append(const_pointer str)
    
{
        size_type nLen 
= strlen(str);
        assert(m_nLen 
+ nLen < m_nBuffSize);
        strcpy(m_str
+m_nLen, str);
        m_nLen 
+= nLen;
        
return *this;
    }


    _Myt
& format(const_pointer sFormat,  )
    
{
        va_list argList;
        va_start( argList, sFormat );
        m_nLen 
= vsprintf(m_str, sFormat, argList);
        va_end( argList );
        assert(m_nLen 
< m_nBuffSize);
        
return *this;
    }


    
//.

protected:
    CMyBaseString(pointer sBuf, size_type nBuffSize)
    
{
        m_nBuffSize 
= nBuffSize;
        m_nLen 
= 0;
        m_str 
= sBuf;
        m_str[
0= 0;
    }


private:
    size_type m_nBuffSize;
    size_type m_nLen;
    pointer m_str;
}
;

template
< size_t _size >
class  CStackString :  public  CMyBaseString
{
public:
    CStackString(
const char* str) : CMyBaseString(m_sMine, _size) { assign(str);}
    CStackString() : CMyBaseString(m_sMine, _size) 
{}

private:
    
char m_sMine[_size];
}
;
int  main()
{
    CStackString
<20> sTest("hello");
    cout 
<< sTest.c_str() << endl;
    cout 
<< sTest.right(3<< endl;
    
return 0;
}

          于是通过基类mybasestring,各种不同类型的template CStackString就又联系在一块了。Mybasestring可看成定义了数据接口的基类,其子类的头部数据必须与它保持一致,嗯,很好。然后,在mybasestring中实现的各种功能,都可以用在mystring身上了,而CStackString中无须实现任何功能,它只负责在堆栈上分配内存。所以,mybasestring不仅可以用在堆栈上,还能用于堆上,只要再继续定义一个能在堆上分配内存的mybasestring的子类即可,然后都能相容于堆栈上的CStackString字符串。

          ……。 经过一番努力,这个字符串类几乎包含了字符数组的一切基本功能,基本上可代替字符数组了。为了能够用到STL中的各种算法,再在其上增加一些返回迭代器的函数,好比beginendrbeginrend,它们都很容易实现。还有,为了使用起来更加友好方便更具效率,貌似应该再实现一些全局操作符的重载运算;……;好了,打住。如果打算将这个字符串很好地融入到STL中,需要做出更多的努力。原本只打算代替字符数组而已。代码在VC2005以上版本编译时,会出现一些警告,可以用#pregma的指令将其disable掉,或者使用其中的所谓的安全字符串操作函数。

          好不容易,终于就实现了一个基于堆栈上的字符串,它是窄字符的。别忘了,还有宽字符的字符串呢。这也没什么,只须将mybasestring重命名为CMyBaseStringACStackString改为CStackStringA。然后再分别实现与CMyBaseStringACStackStringA同样接口的CMyBaseStringWCStackStringW。然后,再针对UNICODETypedefdefined一对CMyBaseStringTCStackStringT。在这里,并不想模仿STL中的stringMFC中的CString那样子,template一个basic_stringsimple_string),然后分别进行模板特化,近来越看越觉得这种模板特化的方式相当恶心,只是将代码搞得更加复杂,却没带来多大的好处。

          相比于其他的字符串实现,这个mybasestring不过是将内存分配拱手让人罢了。这样一来,就带来一些新的问题。首先,它要假设其子类给它分配了足够的内存,不过,在C++传统,经常假设用户分配了足够的内存;然后,因为脱离了内存管理,有一些功能自然也就无法实现出来了,C的字符串函数也还不是这样,当缓冲溢出时,该崩溃就还得崩溃。

          再次向C++的无所不能顶礼膜拜。C++,你是电,你是光, 你是唯一的神话, 我只爱你,You are my Super Star

          再次声明,本字符串只为取代字符数组,至于其它的种种无理要求,均不在本座的考虑范围之内。

你可能感兴趣的:(基于堆栈上的字符串实现)