教你编写STL的string类-01(理解C/C++内存管理)
来源:互联网 发布:网络编程视频教程 编辑:程序博客网 时间:2024/06/05 23:06
STL里的string类相信许多人都用过,它是C++提供的对于字符串操作的类,它与C的字符数组相比,最大的优点就是操作方便,使用它进行存储字符串,或者打印字符串时,不用担心开辟的存储空间是否够用,因为string可以动态增加容纳字符串的空间大小,也不用担心会造成内存泄露,因为析构函数会被自动执行。
现在就来介绍string的实现原理:string的内部实现是依靠一个char*的字符指针,然后根据存储的字符串的大小,动态开辟存储空间。虽然看起简单,如果你不清楚C/C++的内存模型,要实现string是不容易的。以下的例子,因为会用到string.h这个头文件里的函数,所以为了不引起二义性,以_string作为我们编写的仿string类。现在先介绍一个错误的实现:相信很多人第一次实现string时会这么写:
//_string.h
#include <iostream.h>
#include <string>
class _string
{
public:
_string(const char* str=NULL);
_string(const _string& other);
_string operator=(const _string& other);
~_string();
private:
char* m_data;
};
//_string.cpp
#include "_string.h"
_string::_string(const char* str)
{
if(str==NULL)
{
m_data=new char[1];
*m_data=0;
}
else
{
m_data=new char[strlen(str)+1];
strcpy(m_data,str);
}
}
_string::_string(const _string& other)
{
m_data=other.m_data;
}
_string _string::operator=(const _string& other)
{
m_data=other.m_data;
return *this;
}
_string::~_string()
{
delete[] m_data;
}
现在我们在主函数里去使用我们创建的这个类:
//main.cpp
#include "_string.h"
void main()
{
_string s1("Ricky");
_string s2(s1);
_string s3;
s3=s1;
}
此时当我们运行程序时,会出现运行时报错,程序崩溃了。这是为什么呢?问题就出在拷贝构造函数和赋值函数上,为了能理解这个错误,首先必须知道C/C++的内存管理。以上面的为例,当我们创建了s1后,它的m_data指向了一块内存区,该内存区存储的值为Ricky,当我们执行_string s2(s1);时,此时执行了拷贝构造函数,它只是简单的执行了地址的赋值,即s2的m_data也指向了s1的m_data所在的地址空间,s3=s1;也是同样的道理,执行了赋值函数后,只是把s3的m_data指向了s1的m_data所在的地址。这会造成什么结果呢,结果就是当s1,s2,s3依次被析构时,m_data这块地址会被删除3次,同一块地址是不能被删除3次的,所以就造成了运行时崩溃。
那么我们应该怎么做呢,方法有两种:深复制和引用计数。STL的string类就是使用引用计数实现的。不过我们先介绍深复制。
提到深复制,那么就得先说下浅复制,浅复制就是像上面的拷贝构造函数和赋值函数那样,仅仅是进行简单的赋值,所以操作者和被操作者指向的是同一块内存;深复制是单独开辟一块内存,把需要的数据复制到这块内存里面。这样,当我们析构时,删除的就不是同一块内存了,而是自己独有的。下面看看深复制的实现:
为了能显示结果,这里重载了输出操作符<<:
//_string.h
#include <iostream.h>
#include <string.h>
class _string
{
public:
_string(const char* str=NULL);
_string(const _string& other);
_string operator=(const _string& other);
friend ostream& operator<<(ostream& os,const _string& other);
~_string();
private:
char* m_data;
};
//_string.cpp
#include "_string.h"
_string::_string(const char* str)
{
if(str==NULL)
{
m_data=new char[1];
*m_data=0;
}
else
{
m_data=new char[strlen(str)+1];
strcpy(m_data,str);
}
}
_string::_string(const _string& other)
{
m_data=new char[strlen(other.m_data)+1];
strcpy(m_data,other.m_data);
}
_string _string::operator=(const _string& other)
{
if(this==&other)//防止自赋值
return *this;
delete[] m_data;//删除m_data开辟的原有空间
//给m_data开辟新空间并赋值
m_data=new char[strlen(other.m_data)+1];
strcpy(m_data,other.m_data);
return *this;
}
ostream& operator<<(ostream& os,const _string& other)
{
os<<other.m_data;
return os;
}
_string::~_string()
{
delete[] m_data;
}
//main.cpp
#include "_string.h"
void main()
{
_string s1("Ricky");
_string s2(s1);
_string s3;
s3=s1;
cout<<s1<<endl;
cout<<s2<<endl;
cout<<s3<<endl;
}
现在运行程序,不会崩溃,并能正确显示出结果:
下一篇为大家介绍使用引用计数实现string类。
- 教你编写STL的string类-01(理解C/C++内存管理)
- 教你编写STL的string类-02(理解C/C++内存管理)
- STL内存管理的C实现
- 【C++】动态内存管理(五)使用STL容器进行大量的动态内存管理
- [C++]STL string类
- 我理解的objective-C内存管理
- Objective-C的内存管理(二)autorelease的理解
- [C++]String类的理解
- C++STL之string类的使用
- ios学习--Objective C内存管理进阶(一): Iphone开发内存管理的理解
- C++SGI版本STL内存管理
- c 的内存管理
- C的内存管理
- [概念]Objective-C的内存管理,黄金法则的理解
- C++primer学习:拷贝控制(5):动态内存管理类_编写自己的vector
- Objective C内存管理进阶(二):理解autorelease
- Objective C内存管理进阶(二):理解autorelease
- Objective C内存管理进阶(二):理解autorelease
- DAO设计模式---实现一个简单的注册(下)
- 回来冒个泡泡,顺便问下几个问题
- C++中格式控制
- jdbc:oracle:thin 连接问题
- 第十三篇 Android 系统电话管理机制与架构二
- 教你编写STL的string类-01(理解C/C++内存管理)
- ubuntu装机初始化
- SQLite可视化管理工具汇总
- socket方法
- 如何下载并导入SWT包
- socket线程池——ExecutorService应用
- Oracle 安装 Error in writing to directory /tmp/OraInstall 错误 说明
- Eclipse 4.2 安装 SWT 插件教程。
- UML学习(一)