在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
0

只有当字符串被修改的时候才创建各自的拷贝,这种实现方式称为写时复制(copy-on-write)策略。当字符串只是作为值参数(value parameter)或在其他只读情形下使用,这种方法能够节省时间和空间。

不论一个库的实现是不是采用引用计数,它对 string 类的使用者来说都应该是透明的。遗憾的是,情况并不总是这样。在多线程程序中,几乎不可能安全地使用引用计数来实现。

C++ string的内部究竟是什么样的?的更多相关文章

  1. Java 1.7.0_06中String类内部实现的一些变化【转】

    原文链接: java-performance 翻译: ImportNew.com- 夏千林译文链接: http://www.importnew.com/7656.html ChangeLog: 201 ...

  2. 关于JAVA中的String的使用与连接(转)

    JAVA中的String连接性能 Java中的String是一个非常特殊的类,使它特殊的一个主要原因是:String是不可变的(immutable).           String的不可变性是Ja ...

  3. String的内存模型,为什么String被设计成不可变的

    String是Java中最常用的类,是不可变的(Immutable), 那么String是如何实现Immutable呢,String为什么要设计成不可变呢? 前言 关于String,收集一波基础,来源 ...

  4. 从template到DOM(Vue.js源码角度看内部运行机制)

    写在前面 这篇文章算是对最近写的一系列Vue.js源码的文章(https://github.com/answershuto/learnVue)的总结吧,在阅读源码的过程中也确实受益匪浅,希望自己的这些 ...

  5. Java中String连接性能的分析【转】

    [转]http://www.blogjava.net/javagrass/archive/2010/01/24/310650.html 总结:如果String的数量小于4(不含4),使用String. ...

  6. String为什么是不可变的?

    前几天一个面试被问到String为什么是不可变的?, 自我感觉当时回答的不太理想, 事后总结一下 不可变的是什么 我们谈论的String不可变, 指的是字符串的值不可变 例: String s = & ...

  7. JavaScript内部原理实践——真的懂JavaScript吗?(转)

    通过翻译了Dmitry A.Soshnikov的关于ECMAScript-262-3 JavaScript内部原理的文章, 从理论角度对JavaScript中部分特性的内部工作机制有了一定的了解. 但 ...

  8. 【C++探索之旅】第二部分第一课:面向对象初探,string的惊天内幕

    内容简单介绍 1.第二部分第一课:面向对象初探.string的惊天内幕 2.第二部分第二课预告:掀起了"类"的盖头来(一) 面向对象初探,string的惊天内幕 上一课<[C ...

  9. Spring Boot源码探索——自动配置的内部实现

    前面写了两篇文章 <Spring Boot自动配置的魔法是怎么实现的>和 <Spring Boot起步依赖:定制starter>,分别分析了Spring Boot的自动配置和起 ...

随机推荐

  1. java课后作业2019.11.04

    一.编写一个程序,指定一个文件夹,能够自动计算出其总容量 1.代码 package HomeWork; import java.io.File; public class getFileDaxiao ...

  2. 学习tcp和udp

    tcp和udp的差别 tcp和udp是不一样的 tcp是一个可靠的连接,如果发出一个tcp请求,那么就一定要回复一个请求 而udp是不需要回复的,就像QQ一样,只要发过来就可以了,不管别人在不在线,发 ...

  3. MySQL事务(一)认识事务

    简单来说,事务就是要保证一组数据库操作,要么全部完成,要么全部失败. 为什么要有事务 数据库中的数据是共享资源,因此数据库系统通常要支持多个用户的或不同应用程序的访问,会出现并发存取数据的现象. 数据 ...

  4. window下kettle安装

    参考这篇文章 http://note.youdao.com/noteshare?id=a8c536ba952a48d60d7ea8f2cc61a94b

  5. SA-IS学习笔记

    Q:SA-IS 是什么玩意? A:一种 \(O(n)\) 求后缀数组的高科技. Q:为什么会有 SA-IS 这种算法? A:因为它是 \(O(n)\) 的,比倍增 \(O(n\log n)\) 快. ...

  6. 题解-CF436E Cardboard Box

    题面 CF436E Cardboard Box \(n\) 个关卡,对每个关卡可以花 \(a_i\) 时间得到 \(1\) 颗星,或花 \(b_i\) 时间得到 \(2\) 颗星,或不玩.问获得 \( ...

  7. Acwing 393. 雇佣收银员

    算法1: 差分约束 + 枚举 O(Tn2028) 由于牵扯到 \([i - 8 + 1, i]\) 这段区间的和的约束,所以用前缀和更好表达一些. 设 \(num[i]\)表示 \(i\) 时刻有多少 ...

  8. 深入理解Java虚拟机(三)——垃圾回收策略

    所谓垃圾收集器的作用就是回收内存空间中不需要了的内容,需要解决的问题是回收哪些数据,什么时候回收,怎么回收. Java虚拟机的内存分为五个部分:程序计数器.虚拟机栈.本地方法栈.堆和方法区. 其中程序 ...

  9. OpenResty&Canal

    OpenResty&Canal OpenResty 提供缓存功能 封装了Nginx,并且提供了Lua扩展,大大提升了Nginx的并发处理能力10k~1000k Nginx限流 1.控制速率 2 ...

  10. 基数排序(Radix Sort)

    基数排序(Radix Sort) 第一趟:个位 收集: 第二趟:十位 第三趟:百位 3元组 基数排序--不是基于"比较"的排序算法 递增就是把收集的过程返过来 算法效率分析 需要r ...