`
javatoyou
  • 浏览: 1016530 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

C/C++字符串处理(2):String - 常字符串

阅读更多

Table of Contents

概要

我们知道,C++标准库(STL)提供了string(basic_string)类进行字符串操作。字符串很可能除了内存分配器(allocator)1外使用最为频繁的STL类。但是C++社区对string的指责从来就没有停止过。

归纳起来,STL的string类主要有以下这些争议点:

  • 接口过多且规格和其他STL容器没有达成很好的一致性。例如,string::find使用下标,而不是以iterator作为迭代位置,这和其他容器不太一样。
  • 内存碎片。由于过于频繁的字符串构造、析构,导致系统的内存碎片现象严重。
  • Copy -On-Write与多线程安全。string(basic_string)基于Copy-On-Write技术的原因,是因为 string的赋值被设计成为低开销的。但是一旦考虑到多线程安全问题,Copy-On-Write会把大量的时间花在锁的开销上。一些新的STL实现 (如SGI STL)放弃了基于Copy-On-Write的string实现。

我认同这些指责。字符串最好的设计,还是将string分拆为一个常字符串(std::String)和一个字符串操作类(StringBuilder)。我们的StdExt库这样做了。

理解String(BasicString)

StdExt的String(BasicString),和你以前见过的所有字符串类都不太一样。这个类比你想象的还要简单,它只有两个成员变量:

template <class _E>
class BasicString
{
const _E* m_pszBuf;
size_t m_length;
};

它区别于string(basic_string)之处在于:

  • 它是一个常字符串,它永远不会试图去篡改字符串内容(m_pszBuf指向的数据)。
  • 它没有析构,你可以认为其实只是一个结构体。当然,为了方便,BasicString还是有构造函数。
  • 它的m_pszBuf不以nil为结束。而是由m_length成员限定字符串的长度。
  • 它不维护字符串内容(m_pszBuf)的生命周期。如上所述,它没有析构,任何时刻它只是接受或者生成字符串内容,但是不负责销毁它。

最后一点非常重要,也是它的特别之处:它并不维护字符串的生命周期。这可能让你诧异:居然会有这样字符串类,它并不管理字符串的生命周期。

但是我们这样做了。而这的确给我们带来很多便利。例如:

  • 赋值(复制)、子串(substr)是非常轻量的操作。Copy-On-Write技术完全是多余的。
  • 可以将任意的线性容器(如std::vector、std::basic_string)临时转换为String(非常轻量)。参见下文中对String::cast方法的介绍。

为什么String类可以不管理自己的生命周期?这就是我们StdExt的内存管理变革倡导的思想了。

浏览下String类的参考手册,你注意到有这样两个构造函数:

BasicString(const value_type* pszVal, size_type cch);

template <class AllocT>
BasicString(AllocT& alloc, const value_type* pszVal, size_type cch);

这表示:第一个构造函数传入的pszVal,其生命周期比BasicString长(到BasicString析构时仍然有效)。而第二个构造函数的意思是,pszVal是一个临时有效的字符串,这个构造函数将拷贝一个pszVal字符串的副本。

为什么不支持 BasicString(const value_type* pszVal) 这样的构造?

很简单,这个构造过于危险,我不能确定你的意图是什么。

关于TempString基类

从字面意思来讲,这是一个临时字符串类。为什么它会是String(即BasicString)的基类?这其实只是实现上的需要。TempString理论上就是String(只是有特殊的生命周期),和BasicString规格一致。之所以它最后成为BasicString的基类,完全是实现上方便的考虑。

以BasicString::compare为例,我们考察以下这个函数:

int BasicString::compare(const TempString<_E> b) const; 

这个函数的含义非常丰富。相当于定义了以下这一系列的函数:

int BasicString::compare(const _E& b) const; // 与包含单个字符b的字符串比较
int BasicString::compare(const _E* b) const; // 与C Style风格的字符串b比较
int BasicString::compare(const basic_string<_E>& b) const; // 与STL string比较
int BasicString::compare(const BasicString<_E>& b) const; // 与另一个常String比较
int BasicString::compare(const vector<_E>& b) const; // 与向量表示的字符串b比较
int BasicString::compare(const BasicStringBuilder<_E>& b) const;

一个函数可抵6个函数!

已经看到,BasicString中大量使用TempString来进行规格定义。这种方式的代码伸缩性无疑相当好。TempString的构造每增加一种线性字符串的支持,BasicString的所有相关操作即可立即支持该类型的字符串表示。

为了进一步说明这种做法的好处,我们再以字符串连接(concat)作为例子进行说明:

template <class AllocT, class _E> // 多个字符串连接。
BasicString<_E> concat(AllocT& alloc, TempString<_E> a1, TempString<_E> a2, ...);

concat并非是BasicString类的成员函数。而是与BasicString有密切关系的全局函数。对于STL string类,你通常被推荐用operator+或者string::append函数来进行字符串连接。如:

std::string a = std::string("Hello") + " " + "world" + "!!!"; 

而对应地,BasicString并无operator+或者append,它使用全局的std::concat函数进行字符串连接。如下:

std::String a = std::concat(alloc, "Hello", " ", "world", "!!!"); 

有意思的是,这个std::concat不只可以高效地连接任意多的字符串,而且,它还可以连接高效地连接各种线性的字符串表示,包括:char*, std::string, std::vector<char>, std::String, std::StringBuilder等。例如:

std::string hello = "Hello";
std::String space(" ", 1);
std::vector<char> excalmatory_mark(3, '!');
std::String a = std::concat(alloc, hello, space, "world", excalmatory_mark);

这其中的奥秘,全在TempString上。关于std::TempString的详细说明,参见TempString

源码

StdExt库的工程主页:http://code.google.com/p/stdext/

参考阅读

分享到:
评论

相关推荐

    C++ 模板写的短小字符串类,用于替换字符数组和std::string

    //短小字符串类 template struct TinyString { TinyString(); template&lt;size_t K&gt; TinyString(const TinyString&lt;K&gt;& str); TinyString(size_t n, char c); TinyString(const char* s, size_t n=0...

    详解C++ string常用截取字符串方法

    string常用截取字符串方法有很多,但是配合使用以下两种,基本都能满足要求: find(string strSub, npos); find_last_of(string strSub, npos); 其中strSub是需要寻找的子字符串,npos为查找起始位置。找到返回子...

    string-width:获取字符串的可视宽度-显示字符串所需的列数

    字符串宽度 获取字符串的可视宽度-显示字符串所需的列数 某些Unicode字符为并且使用正常宽度的两倍。 被剥离,并且不影响宽度。 有助于测量命令行输出的实际宽度。 安装 $ npm install string-width 用法 import ...

    C语言字符串函数大全C/C++基础 字符串操作大全

    C语言字符串函数大全C/C++基础 函数名: stpcpy 功 能: 拷贝一个字符串到另一个 用 法: char *stpcpy(char *destin, char *source); 程序例: #include &lt;stdio.h&gt; #include &lt;string.h&gt; int main(void) ...

    C++17 使用 std::string_view避免字符串拷贝优化程序性能

    C++中std::string是日常Coding中经常使用的一个类,使用起来非常方便,但是也存在一些弊端。 如下代码,参数传递的过程发生了内存分配(Memory ...再看下面的常用的字符串截取实现: // very long string std::strin

    C++ 汉字UTF-8字符串处理类库

    很多人喜欢用CString 或std:string,但是他们的缺点是不能完成汉字各种类型之间的转换,提供三种类库ascString,ucsString,utfString以及工具utfCount,utf8_ucs2_t,tcf8_ucs4_t类库,用于各种字符串之间的直接转换`...

    C++常用字符串分割方法实例汇总

    本文实例汇总了C++常用字符串分割方法,分享给大家供大家参考。具体分析如下: 我们在编程的时候经常会碰到字符串分割的问题,这里总结下,也方便我们以后查询使用。 一、用strtok函数进行字符串分割 原型: char *...

    C/C++字符串的排序、粘贴与转型

    字符串的粘贴(全部粘贴、定长粘贴和是否允许字符串中包含空格); 字符串的排序; 代码使用的文件之间调用的方式,最终在主函数被调用使用。 代码基于VS2010编写,在VS2010以下版本可能无法点击工程文件直接运行,...

    C++——字符串变量.txt

    处理字符串,除了字符数组,还有用C++的string类型来定义一个字符串变量(对象)。 定义字符串并进行初始化: string string1="chance"; 注意:必须要有头文件# include &lt;string&gt;; 比较:字符数组不能直接对字符...

    std::string、char*、const char*转托管byte数组或托管字符串String

    std::string、char*、const char*转托管byte数组或托管字符串String

    详解C++中十六进制字符串转数字(数值)

    详解C++中十六进制字符串转数字(数值) 主要有两个方法,其实都是对现有函数的使用:  方法1: sscanf()  函数名: sscanf 功 能: 从字符串格式化输入 用 法: int sscanf(char *string, char *format[,...

    C++ XMind关于std::string总结

    在任何编程语言中,字符串都是重中之重。通过使用XMind总结C++ XMind中的字符串,了解并熟练掌握string对象的构造和初始化,插入删除替换,查找和比较,把所有相关的操作整合在一个页面上,提高工作效率

    C/C++代码高亮修饰软件

    字符串和字符 --- 暗红色 字体为 VC++6.0 的默认字体 fixedsys ,代码配色方案为 VS2008 默认配色方案。 该软件可对 ".h" ".c" ".cpp" ".txt" 格式的文件转换为 ".html"格式的网页文件。 在浏览器下显示高亮代码...

    bcrypt库C/C++使用

    bcrypt库C/C++使用 ```cpp #include "bcrypt/BCrypt.hpp" #include int main(){ std::string password = "123456"; //此函数用于生成hash字符串 std::string hash = BCrypt::generateHash(password); //用于...

    C/C++字符串函数之复制函数详解

    C/C++字符串函数的头文件:string.h 复制函数主要有4个,如下: 1、char * strcpy(char* destination,const char * source); 2、char* strncpy(char* destination,const char* source,size_t num); 3、void * ...

    C++中string类的使用说明(保姆级说明)

    在C++中,`std::string` 类已经提供了丰富的方法来处理字符串,以下是 `std::string` 类的一些常用方法: 1. 构造函数: - `string()`: 默认构造函数,创建一个空字符串。 - `string(const char* s)`: 使用 C ...

    字符串/通配符匹配(C++)

    C++实现字符串匹配函数,匹配中可以包括通配符

    C/C++的split分隔字符串

    标准C/C++编写的字符串分隔函数,可以设置分隔字符串,解出字符串存到vector里面。有需要的可以下载

    各种 C++ 字符串类型转换

    各种 C++ 字符串类型转换(char *、wchar_t*、_bstr_t、CComBSTR、CString、basic_string 和 System.String) 本主题演示如何将各种 C++ 字符串类型转换为其他字符串。可以转换的字符串类型包括 char *、wchar_t*、_...

    hash字符串函数总结

    hash字符串函数总结,挥泪大放送,绝对全面,各类总结。

Global site tag (gtag.js) - Google Analytics