文章目录
- 一、string原理介绍
- 二、仅介绍MSVC和GCC编译器对于string的不同实现
- 三、string的坑
- 四、注意点
- 1)std string是一个char vector,它保存的是自己本身,因此对于ascii字节和宽字节,它需要不同的容器去实现
- 2)不支持split,find & substr即可解决,何况还有几个加强版的find, 虽然在C++11中,你可以使用更通用的闭包版本来解决,但他的确提供了几个方便又好理解的加强版:find_first_of, find_last_of, find_first_not_of, find_last_not_of;
- 3)C++11明确规定了字符串以\0结尾了。为的是data()能兼容c风格字符串
- 4)string是模板的标准库,effectiveC++不建议继承
- 5)copy_on_write与多线程有安全问题.
- 6)std::string无法作为dll接口参数
一、string原理介绍
1)内部数据结构
①三指针(类似vector)
(1)数据起始段,begin of the allocated region and data
(2)数据终止段,end of data
(3)数据存到现在buffer的哪个位置了, a pointer (begin of allocated region and data)
②两整数:
(1)存储字母的数量,number of characters in the string
(2)分配buffer的字节数,number of allocated bytes
2)工作机制(更细节涉及到对应编译器不同平台的具体实现)
(1)步骤
0)一开始若小于24字节,就默认分配24字节的内存区域
1)当新赋值字符串,如果分配的内存还有余额或整块内存都可以放得下字符串数据,那么就在第三个指针后面更新数据;
2)当余额buffer内存不够来存储了,那就动态分配更多内存来字符串,有的说是1.5倍所需内存或2倍所需内存,than the alternative of growing by a single allocation block.,然后把自己的原先内容拷贝过去
- 缺点
因为要从原先的地方拷贝,所以效率不好
(2)替代者
一个是 Facebook folly 出品的 FBString ,另一个是 Google 出品的 StringPiece,例如 leveldb 中的 Slice
-
- StringPiece什么是 StringPiece ?A string-like object that points to a sized piece of memory说白了就是string的只读视图,为了便于解释,直接来看代码吧:void func(const std::string & str);
const & 限定了 函数 func 没法修改入参 str,但是如果给 func 传递的参数是 char * 或者 const char *,那么将构造一个临时的 std::string,并且产生了字符串的拷贝,但是显然这次拷贝并没有必要。StringPiece 就是在这种情况去替换 std::string,可以避免字符串拷贝,因为 StringPiece 只是简单接管一下指针,看一下 StringPiece 的简单实现就知道了,这里以 leveldb 中的 Slice 为例子,看一下其构造函数就明白了
- StringPiece什么是 StringPiece ?A string-like object that points to a sized piece of memory说白了就是string的只读视图,为了便于解释,直接来看代码吧:void func(const std::string & str);
class LEVELDB_EXPORT Slice {
public:
......
Slice(const char* d, size_t n) : data_(d), size_(n) { }
......
private:
const char* data_;
size_t size_;
};
-
- FBStringFBString 是 facebook 开源 C++ lib folly 的一个 std::string 替换着,如果你想更好的性能,又不想重写,那么 FBString 是一个不错的选择,Facebook 对其做了大量的性能优化,其核心特点如下:100% 兼容 std::string高性能的内存管理,对不同大小的字符串, 分 3 种情况分配和管理内存:
(1)string length <= 23,使用栈上内存;
(2)23< string length <=255,使用 malloc 分配堆上内存;
(3)string lenght > 255,堆上内存,且使用引用计数 + COW 计数,实现在真正需要的时候才拷贝修改,避免大字符串不必要的拷贝find 操作使用了 Boyer Moore [3] 算法,
- 性能
相比 O(n) 的 KMP 实际性能好很多,Facebook 官方宣称性能:Casual tests indicate a 30x speed improvement overstring::find()for successful searches and a 1.5x speed improvement for failed searches感兴趣的可以去了解使用下。实际上没有最好,只有最合适,就看 std::string 是否满足你的需求
二、仅介绍MSVC和GCC编译器对于string的不同实现
- gcc
gcc4.8.5之前都是COW, - MSVC
MSVC debug下无任何优化,release下是SSO - SSO解释
SSO是短/小字符串优化。 std::string 通常,A 将字符串存储为指向免费存储区(“堆”)的指针,该存储区具有与调用相似的性能特征 new char [size] 。 这样可以防止非常大的字符串出现堆栈溢出,但是这样做可能会更慢,尤其是对于复制操作而言
三、string的坑
1)C++中string.size()函数 踩坑
- 原因
例如string、vector等类型的size函数返回的是一个无符号整型数 - 解释
带符号数将自动转换为无符号数,例如-1,由于-1的二进制表示的最高位为1,这回导致size() > -1一定会返回false。在进行判断size()时,还是应该使用0进行比较。 - 错误实例
#include<iostream>
#include<string>
using namespace std;
int main(){
string haystack = "";
string needdle = "a";
int i=0;
cout<<haystack.size()<<endl;
cout<<needdle.size()<<endl;
cout<<haystack.size()-needdle.size();
return 0;
}
haystack的长度为0,needle的长度为1,而 无符号的 0减1 时出现了如下情况
- 结果