C++ string介绍和坑

一、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

    1. 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 为例子,看一下其构造函数就明白了
class LEVELDB_EXPORT Slice {
 public:
  ......
  Slice(const char* d, size_t n) : data_(d), size_(n) { }
  ......
 private:
  const char* data_;
  size_t size_;
};    
    1. 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 时出现了如下情况

  • 结果
    在这里插入图片描述

2)官网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接口参数

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值