C++string的内部究竟是什么样的?
在C语⾔中,有两种⽅式表⽰字符串:
⼀种是⽤字符数组来容纳字符串,例如char str[10] = "abc",这样的字符串是可读写的;
⼀种是使⽤字符串常量,例如char *str = "abc",这样的字符串只能读,不能写。
两种形式总是以\0作为结束标志。
C++ string 与它们在C语⾔中的前⾝截然不同。⾸先,也是最重要的不同点,C++ string 隐藏了它所包含的字符序列的物理表⽰。程序设计⼈员不必关⼼数组的维数或\0⽅⾯的问题。
string 在内部封装了与内存和容量有关的信息。具体地说,C++ string 对象知道⾃⼰在内存中的开始位置、包含的字符序列以及字符序列长度;当内存空间不⾜时,string 还会⾃动调整,让内存空间增长到⾜以容纳下所有字符序列的⼤⼩。
C++ string 的这种做法,极⼤地减少了C语⾔编程中三种最常见且最具破坏性的错误:
数组越界;
通过未被初始化或者被赋以错误值的指针来访问数组元紊;
释放了数组所占内存,但是仍然保留了“悬空”指针。
C++ 标准没有定义 string 类的内存布局,各个编译器⼚商可以提供不同的实现,但必须保证 string 的⾏为⼀致。采⽤这种做法是为了获得⾜够的灵活性。
特別是,C++ 标准没有定义在哪种确切的情况下应该为 string 对象分配内存空间来存储字符序列。string 内存分配规则明确规定:允许但不要求以引⽤计数(reference counting)的⽅式实现。但⽆论是否采⽤引⽤计数,其语义都必须⼀致。
C++ 的这种做法和C语⾔不同,在C语⾔中,每个字符型数组都占据各⾃的物理存储区。在 C++ 中,独⽴的⼏个 string 对象可以占据也可以不占据各⾃特定的物理存储区,但是,如果采⽤引⽤计数避免了保存同⼀数据的拷贝副本,那么各个独⽴的对象(在处理上)必须看起来并表现得就像独占地拥有各⾃的存储区⼀样。例如:
// #include<bits/stdc++.h>
#include <iostream>
#include <string>
字符串常量实质
using namespace std;
int main() {
string s1("12345");
string s2 = s1;
cout << (s1 == s2) << endl;
s1[0] = '6';
cout << "s1 = " << s1 << endl;  // 62345
cout << "s2 = " << s2 << endl;  // 12345
cout << (s1 == s2) << endl;
return 0;
}
在 GCC 下的运⾏结果:
1
s1 = 62345
s2 = 12345
只有当字符串被修改的时候才创建各⾃的拷贝,这种实现⽅式称为写时复制(copy-on-write)策略。当字符串只是作为值参数(value parameter)或在其他只读情形下使⽤,这种⽅法能够节省时间和空间。
不论⼀个库的实现是不是采⽤引⽤计数,它对 string 类的使⽤者来说都应该是透明的。遗憾的是,情况并不总是这样。在多线程程
序中,⼏乎不可能安全地使⽤引⽤计数来实现。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。