《STL字符串现代实现:从UTF-8处理到写时拷贝的线程安全难题(终章)》

目录

再谈swap

构造的现代写法

写时拷贝

string类在什么情况下触发写时才拷贝(Copy-On-Write)?

编码

unicode

utf-8

其他编码

编码常见问题

string的编码


再谈swap

我们乍一看,为什么有三个swap函数呢?

算法库里面的swap,我们经常用,我们也知道,他们交换的时候需要构建临时变量,开空间,拷贝数据,再释放。代价是非常高的。于是这里我们引入了引用来解决这些问题。

对于两个 string 对象的交换 , 仅仅改变指向 不久可以了吗 ? string 的成员函数也的确是这么做的 。(复用了算法库的swap ! 仅仅是内部指针指向的交换) 

	void string::swap(string& s)
	{
		std::swap(_str, s._str);
		std::swap(_size, s._size);
		std::swap(_capacity, s._capacity);
	}

但是实际上,当我们去调用swap,编译器并不会调用算法库内的swap,优先调用string 的全局函数swap,而且全局函数的swap 是对成员函数 swap 的封装。

构造的现代写法

拷贝构造

	//传统写法
	string::string(const string& s)
	{
		_str = new char[s._capacity + 1];
		strcpy(_str, s._str);
		_size = s._size;
		_capacity = s._capacity;

其实下面要介绍的现代写法 , 没有效率的提升 , 只是简洁一点 ,本质是一种复用 

	//现代写法
	string::string(const string& s)
	{
		string tmp(s._str);
		swap(tmp);
	}

现代写法借助了tmp来构造,s._str 是深拷贝的源头,调用成员函数 swap,交换 *this 与 tmp 的资源,交换后,*this 获得 tmp 的资源(就是拷贝后的字符串),而 tmp 持有原对象的空/无效状态。

赋值重载

	//传统写法
	string& string::operator=(const string& s)
	{
		if (this != &s)
		{
			delete[] _str;
			_str = new char[s._capacity + 1];
			strcpy(_str, s._str);
			_size = s._size;
			_capacity = s._capacity;
		}
 
		return *this;
	}
string& string::operator=(const string& s)
{
	if (this != &s)
	{
		string tmp(s._str);
		swap(tmp);
	}
 
	return *this;
}//现代

这里还可以更加简洁一些   

	string& string::operator=(string& s)
	{
		swap(s);
		return *this;
	}

写时拷贝

1. 写时拷贝 : 就是一种拖延症 , 是再浅拷贝的基础之上增加了引用计数的方式来实现 。

2. 引用计数 : 用来记录资源使用者的个数 , 在构造时 , 将资源的计数给成1 , 每增加一个对象使用该资源 , 就给计数增加 1 , 当某个对象被销毁时 , 先给该计数减 1 , 然后再检查是否需要释放资源 , 如果计数为  1 , 说明该对象是资源的最后一个使用者 , 将该资源释放 , 否则就不能释放 , 因为还有其他对象在使用该资源 。

其实就是为了解决浅拷贝导致的问题 (析构多次,程序崩溃; 一个对象的修改影响另一个对象)

这个方式其实现在差不多都淘汰了 ,早期的g++使用 ,现在基本不用。

string类在什么情况下触发写时才拷贝(Copy-On-Write)?

哦,什么时候会发现写时才拷贝?很显然,当然是在共享同一块内存的类发生内容改变时,才会发生Copy-On-Write。比如string类的[]、=、+=、+、操作符赋值,还有一些string类中诸如insert、replace、append等成员函数,包括类的析构时。

修改数据才会触发Copy-On-Write,不修改当然就不会改啦。这就是托延战术的真谛,非到要做的时候才去做。

接下来我们再来了解一些特殊的编码

编码

unicode

统一码(Unicode),也叫万国码、单一码,由统一码联盟开发,是计算机科学领域里的一项业界标准,包括字符集、编码方案等。

统一码是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言,跨平台进行文本转换、处理的要求。

简单说,它是一个 超级大字典,收录了 14 万 + 字符,覆盖全球 150 + 语言,甚至包括 ** extinct languages(已灭绝的语言)。

unicode实际上覆盖一切:

语言:中文(简体 + 繁体)、英文、日文、韩文、阿拉伯文、希伯来文、希腊文、俄文……
符号:数学符号(∑√π)、货币符号(¥€$)、箭头(→↑)、标点(!?)。
表情:😂👍❤️🌍✨(emoji 本质是 Unicode 字符)。
特殊文字:盲文、古埃及圣书体、克林贡语(《星际迷航》里的外星语)……
甚至有 私人使用区(PUA),你可以自己造字!
版本更新:每年新增字符(比如 2023 年加入了 🩷🤌🦖),跟上时代。

跨平台兼容:所有现代系统(Windows、macOS、Linux)、编程语言(Python、Java、JavaScript)都默认支持 Unicode。

utf-8

Unicode 给每个字符发了 “身份证”(码点),但直接存身份证号太浪费空间(比如英语字母本来 1 字节够,硬存成 4 字节纯纯浪费)。而utf-8 , 变长编码 , 而且还兼容 ASCII 码 。

核心优点省空间 + 兼容 ASCII + 无乱码,所以现在几乎所有系统、网页、编程语言都默认用它(比如你现在看的这行字,大概率就是 UTF-8 编码的)。

其他编码

(1)GBK / GB18030(中文编码)

GB2312:早期简体中文(6763个汉字)。
GBK:扩展版(支持繁体、生僻字)。
GB18030:强制国家标准,兼容Unicode。

(2)Big5(繁体中文)

主要用于港台地区。

(3)Shift-JIS(日文)

日本Windows系统传统编码。

编码常见问题

为什么文本乱码?

可能是文件保存时用了错误的编码(比如用 GBK 存,用 UTF-8 打开)。解决办法:统一用 UTF-8 编码保存和读取。

UTF-8 和 UTF-16 选哪个?

  • 文本以英语为主:选 UTF-8(省空间)。
  • 文本以中文 / 日文为主:选 UTF-16(省 1/3 空间,但兼容性略差)。
  • 编程推荐用 UTF-8(几乎所有工具默认支持)。

BOM 是什么

UTF-16 文件开头可能有 FF FE 或 FE FF用来标记 “大端序” 或 “小端序”(类似告诉电脑 “先读左边还是右边”)。UTF-8 一般不需要 BOM。 

string的编码

我们在文档里面经常看到类似于这种,实际上在编程中,string 以及后面的 u16string(对应 char16)、u32string(对应 char32)、wstring(对应 wchar) 存在 , 主要是为了适应不同的字符编码需求以及处理不同特性的文本 。

评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值