您的位置:首页 > 编程语言 > C语言/C++

c++中string类的基本功能的实现(1)

2016-05-29 17:22 615 查看
1、传统的实现string类的方法
优点:程序简单易懂
缺点:
1)在实现其拷贝构造和赋值的操作时多次的调用new动态的开辟空间,因此也需要多次的通过delete来释放空间。如果处理不当还容易造成内存泄漏。
2)程序的一致性比较差
2、现代的实现string类的方法写实
拷贝构造实现思路:
a)创建一个临时对象,并通过cconst String._str来构造。
b)构造完成之后将临时对象的_str和this._str进行交换进而使得对象的内容交换来完成拷贝构造
赋值实现思路:
通过参数的值传递来构造对象,并将对象的内容交换
优点:
1)程序的一致性比较好
2)只是在构造函数中出现了开辟空间的new,只在析构函数中出现了delete结构清晰,不容易造成内存泄漏
class String
{
public:
// 构造函数
String(char *str = "")
:_str(new char [strlen(str)+1])
{
if (_str != NULL)
{
strcpy(_str, str);
}
}

//拷贝构造
String(const String& str)
:_str(NULL)//防止其指向一份不合法的空间
{
String tmp(str._str);
swap(_str, tmp._str);
}

//赋值
String& operator =(String str)
{
swap(_str, str._str);
return *this;
}

//析构函数
~String()
{
delete [] _str;
}
private:
char * _str;
};


3、写实函数提高string类的效率
在以上的两种string类的实现方法中,都存在一个效率的问题。有的时候字符串比较长,而且对象建立之后也不一定更改。但是以上两种方法无论何时都需要构建,其效率比较低而且会带来内存的浪费。
我们可以通过让所有指向相同字符串内容的对象指向同一份空间,通过计数器来记录对象的个数,避免析构出现错误。
所以可以通过在开辟对象的时候多开辟4个字节的空间,来存放计数器。如果修改的时候再开辟空间。
#define _CRT_SECURE_NO_WARNINGS

#include<iostream>
#include <string>
using namespace std;

class String
{
public:
//构造函数
String(char *str="")
:_Pstr(FindStartRef(new char[strlen(str)+1+sizeof(int)]))
{
*Count(_Pstr) = 1;//计数器
strcpy(_Pstr, str);//将字符串拷贝
}

//拷贝构造函数
//如果不更改对象的内容则让多个对象的字符指针指向同一份空间
String(const String& s)
{
_Pstr = s._Pstr;
(*Count(_Pstr))++;//计数器加1
}

//赋值语句
//如果不更改对象的内容则让多个对象的字符指针指向同一份空间
String& operator =(const String& s)
{
if (this != &s)//避免自赋值
{
if (--*(Count(_Pstr)) == 0)
{
delete[]FindDel(_Pstr);
}//只有一个对象使用的一份空间则释放
else
{
_Pstr = s._Pstr;
(*Count(_Pstr))++;
}
}
return *this;
}

//析构函数
~String()
{
if (--*(Count(_Pstr)) == 0)
{
delete[]FindDel(_Pstr);
}
}
public:
//找到开辟空间时的存放字符串的首地址
char * FindStartRef(char* str)
{
return (str + 4);
}

//找到释放空间时的首地址
char * FindDel(char* del)
{
return (del - 4);
}

//找到计数器的首地址
int *Count(char* str)
{
return (int *)(str - 4);
}
public:
//修改写实对象的内容函数
char & operator[](int index)
{
if (--*(Count(_Pstr)) != 0)
{
char * tmp = _Pstr;
_Pstr = FindStartRef(new char[strlen(_Pstr) + 1 + sizeof(int)]);
*Count(_Pstr) = 1;//计数器置1
strcpy(_Pstr, tmp);
}//如果该对象和其他对象公用一份空间
else
{
//单独使用一份空间可以随意更改
}
return _Pstr[index];
}
private:
char * _Pstr;
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: