标准C++类std::string的
内存共享和Copy-On-Write技术
陈皓
1、 概念
Scott Meyers在《More Effective C++》中举了个例子,不知你是否还记得?在你还在上学的时候,你的父母要你不要看电视,而去复习功课,于是你把自己关在房间里,做出一副正在复习功课的样子,其实你在干着别的诸如给班上的某位女生写情书之类的事,而一旦你的父母出来在你房间要检查你是否在复习时,你才真正捡起课本看书。这就是“拖延战术”,直到你非要做的时候才去做。
当然,这种事情在现实生活中时往往会出事,但其在编程世界中摇身一变,就成为了最有用的技术,正如C++中的可以随处声明变量的特点一样,Scott Meyers推荐我们,在真正需要一个存储空间时才去声明变量(分配内存),这样会得到程序在运行时最小的内存花销。执行到那才会去做分配内存这种比较耗时的工作,这会给我们的程序在运行时有比较好的性能。必竟,20%的程序运行了80%的时间。
当然,拖延战术还并不只是这样一种类型,这种技术被我们广泛地应用着,特别是在操作系统当中,当一个程序运行结束时,操作系统并不会急着把其清除出内存,原因是有可能程序还会马上再运行一次(从磁盘把程序装入到内存是个很慢的过程),而只有当内存不够用了,才会把这些还驻留内存的程序清出。
写时才拷贝(Copy-On-Write)技术,就是编程界“懒惰行为”——拖延战术的产物。举个例子,比如我们有个程序要写文件,不断地根据网络传来的数据写,如果每一次fwrite或是fprintf都要进行一个磁盘的I/O操作的话,都简直就是性能上巨大的损失,因此通常的做法是,每次写文件操作都写在特定大小的一块内存中(磁盘缓存),只有当我们关闭文件时,才写到磁盘上(这就是为什么如果文件不关闭,所写的东西会丢失的原因)。更有甚者是文件关闭时都不写磁盘,而一直等到关机或是内存不够时才写磁盘,Unix就是这样一个系统,如果非正常退出,那么数据就会丢失,文件就会损坏。
呵呵,为了性能我们需要冒这样大的风险,还好我们的程序是不会忙得忘了还有一块数据需要写到磁盘上的,所以这种做法,还是很有必要的。
2、 标准C++类std::string的Copy-On-Write
在我们经常使用的STL标准模板库中的string类,也是一个具有写时才拷贝技术的类。C++曾在性能问题上被广泛地质疑和指责过,为了提高性能,STL中的许多类都采用了Copy-On-Write技术。这种偷懒的行为的确使使用STL的程序有着比较高要性能。
这里,我想从C++类或是设计模式的角度为各位揭开Copy-On-Write技术在string中实现的面纱,以供各位在用C++进行类库设计时做一点参考。
在讲述这项技术之前,我想简单地说明一下string类内存分配的概念。通过常,string类中必有一个私有成员,其是一个char*,用户记录从堆上分配内存的地址,其在构造时分配内存,在析构时释放内存。因为是从堆上分配内存,所以string类在维护这块内存上是格外小心的,string类在返回这块内存地址时,只返回const char*,也就是只读的,如果你要写,你只能通过string提供的方法进行数据的改写。
2.1、 特性
由表及里,由感性到理性,我们先来看一看string类的Copy-On-Write的表面特征。让我们写下下面的一段程序:
#include<stdio.h></stdio.h>
#include <iostream></iostream>
using namespace std;
main()
{
string str1 = "hello world";
string str2 = str1;
printf ("Sharing the memory:\n");
printf ("\tstr1's address: %x\n", str1.c_str() );
printf ("\tstr2's address: %x\n", str2.c_str() );
str1[1]='q';
str2[1]='w';
printf ("After Copy-On-Write:\n");
printf ("\tstr1's address: %x\n", str1.c_str() );
printf ("\tstr2's address: %x\n", str2.c_str() );
return 0;
}
|
这个程序的意图就是让第二个string通过第一个string构造,然后打印出其存放数据的内存地址,然后分别修改str1和str2的内容,再查一下其存放内存的地址。程序的输出是这样的(我在VC6.0和g++ 2.95都得到了同样的结果):
> g++ -o stringTest stringTest.cpp
> ./stringTest
Sharing the memory:
str1's address: 343be9
str2's address: 343be9
After Copy-On-Write:
str1's address: 3407a9
str2's address: 343be9
|
从结果中我们可以看到,在开始的两个语句后,str1和str2存放数据的地址是一样的,而在修改内容后,str1的地址发生了变化,而str2的地址还是原来的。从这个例子,我们可以看到string类的Copy-On-Write技术。
下一页->
(版权所有,转载时请注明作者和出处)
分享到:
相关推荐
STL 字符串可以分为两类:copy-on-write 字符串和非 copy-on-write 字符串。copy-on-write 字符串在修改字符串时,会创建字符串的副本,而非 copy-on-write 字符串则不会创建副本。非 copy-on-write 字符串的性能...
在C++编程中,字符串处理是...总的来说,`String`类的实现利用了预分配内存和Copy-on-Write技术,旨在提供一种高效且易于使用的字符串处理工具。理解这些技术可以帮助我们在设计和实现自定义数据结构时更好地优化性能。
- **优化字符串复制**:对于频繁复制的场景,可以考虑引入“写时复制”(Copy-On-Write, COW)机制来提高效率。 - **预分配空间**:对于预期会增长的字符串,可以在构造函数中预分配一定的额外空间,以减少后续重新...
写时拷贝(Copy-on-Write,COW)则是在尝试修改对象时才进行拷贝,如果只是读取,则可以共享同一份数据,节省内存。 在C++中,我们可以通过使用`std::shared_ptr`或`std::atomic`等工具来实现这一策略。以下是一些...
老实说,我几年前也有同样的痛苦(就是当我写下《标准C++类string的Copy-On-Write技术》之前的一段时间)。那时,我不得不研究那根本不是给人看的SGI出品的string类的源码,代码的可读性几乎为零,而且随着了解越...
接着,`MyString(v2.0)`引入了"写时拷贝"(Copy-on-Write, COW)策略,配合引用计数来提高效率。当两个字符串共享同一内存区域时,只有在其中一个字符串被修改时才真正进行拷贝。引用计数用于跟踪共享同一个数据结构...
special offer, and write for full details on how to receive a free IntroPak containing a $15 credit toward your first month's on-line charges. 2. Check with your local software dealer or users' ...
C++标准库中的`std::string`类采用了Copy-On-Write技术,在字符串拷贝或赋值操作时延迟实际的内存复制,直到某个操作需要修改字符串内容时才进行复制,从而提高了程序的效率。 以上知识点涵盖了从基础语法到高级...
special offer, and write for full details on how to receive a free IntroPak containing a $15 credit toward your first month's on-line charges. 2. Check with your local software dealer or users' ...
Earlier versions of Delphi and C++ Builder will not be supported. If you need Delphi 3 or C++ Builder 3 support you will have to revert to version 3.7 of the Drag and Drop Component Suite. The ...
Classes Doing Work in Constructors Default Constructors Explicit Constructors Copy Constructors Structs vs. Classes Inheritance Multiple Inheritance Interfaces Operator Overloading Access Control ...
基于 C++ 的多线程拷贝技术 本文讲述基于 C++ 的多线程拷贝技术,包括实现流程和源代码程序。多线程拷贝技术可以大大提高文件拷贝速度,特别是在拷贝大文件时。 多线程拷贝技术实现流程 1. 把一个文件分成 N 份,...
`std::string`类型是C++中的一个类,可以方便地进行字符串的操作,避免了C语言中使用字符数组带来的诸多不便。 容器库(container)是STL(Standard Template Library,标准模板库)的一部分,包括向量(vector)、...
- **格式转换**:使用`avformat_open_input`打开输入文件,`avformat_find_stream_info`获取流信息,`avformat_write_header`写入输出文件头部,然后读取AVPacket并用`av_interleaved_write_frame`写入输出文件,...
C++是一种广泛使用的编程语言,以其强大的功能和灵活性而闻名。C++库函数大全是学习和使用C++不可或缺的资源,它包含了丰富的内置库函数,这些函数极大地扩展了语言的基本功能,使得开发者能够高效地处理各种任务。...
自定义字符串类的性能优化方面,考虑到std::string在某些情况下可能进行不必要的内存复制操作,开发者可能会通过使用引用计数、移动语义(C++11引入)、写时复制(copy-on-write)等策略来优化性能。此外,自定义...
第1章 计算机与C++编程简介 1.1 简介 1.2 什么是计算机 1.3 计算机组成 1.4 操作系统的变革 I.5 个人计算、分布式计算与客户/a匠务器计算 l. 6 机器语言、汇编语言和高级语言 1.7 C语言与C++的历史 1.8 C++...