什么是深浅拷贝?
定义字符串char* str1="hello";
现在定义一个字符串char* str2和str1的数据相同,这种情况分两种;
- str1和str2数据和空间都相同,即str2指向str1 的地址空间。
- str2另开辟空间,再将str1的数据拷贝给str2,即str1和str2数据相同,指向的地址不同。
第一种情况叫做浅拷贝,第二种情况叫做深拷贝
而在C++中,使用浅拷贝容易发生很严重的代码事故---内存泄漏
str1和str2指向同一段地址空间,而析构函数是系统自动生成并调用,会产生一段空闲析构两次的情况。
下面使用深浅拷贝的传统写法和现代写法实现String类:
传统写法和现代写法主要区别在于拷贝构造函数和赋值操作符重载函数里写法不同,如下;
拷贝构造函数的不同写法:
void Swap(String& s)
{
swap(_str,s._str);
swap(_size,s._size);
swap(_capacity,s._capacity);
}
//传统写法
String(const String& s)
:_str(new char[strlen(s._str)+1])
{
strcpy(_str,s._str);
}
//现代写法
String(const String& s)
:_str(NULL)
{
String tmp(s._str);
Swap(tmp);
}
赋值运算符重载函数的不同写法:
现代写法
String& operator=(const String& s){
if(this!=&s){
String tmp(s._str);
swap(_str,tmp._str);
}
return *this;
}
最好的现代写法
String& operator=(String s){
if(this!=&s){
Swap(s);
return *this;
}
}
//传统写法
//s1=s2,s2的长度可能超过s1的空间
//如果只是值拷贝,同一个空间会析构两次,导致内存泄漏
//要先释放空间
String& operator=(const String& s)
{
if(this!=&s){
delete[] _str;
char* tmp=new char[strlen(s._str)+1];
strcpy(tmp,s._str);
_str=tmp;
}
return *this;
}
全部代码实现:
#pragma once
#include<iostream>
#include<string.h>
#include<assert.h>
using namespace std;
//1.传统写法
//2.现代写法 拷贝构造和赋值有新的写法
class String{
public:
String(const char* str)
:_size(strlen(str))
,_capacity(_size)
{
_str=new char[_size+1];
strcpy(_str,str);
}
void Swap(String& s)
{
swap(_str,s._str);
swap(_size,s._size);
swap(_capacity,s._capacity);
}
//s1(s);深拷贝
String(const String& s)
:_str(new char[strlen(s._str)+1])
{
strcpy(_str,s._str);
}
//现代写法
/* String(const String& s)
:_str(NULL)
{
String tmp(s._str);
Swap(tmp);
}
现代写法
String& operator=(const String& s){
if(this!=&s){
String tmp(s._str);
swap(_str,tmp._str);
}
return *this;
}*/
最好的现代写法
String& operator=(String s){
if(this!=&s){
Swap(s);
return *this;
}
}
//s1=s2,s2的长度可能超过s1的空间
//如果只是值拷贝,同一个空间会析构两次,导致内存泄漏
//要先释放空间
/*String& operator=(const String& s)
{
if(this!=&s){
delete[] _str;
char* tmp=new char[strlen(s._str)+1];
strcpy(tmp,s._str);
_str=tmp;
}
return *this;
}
*/
~String(){
if(_str){
delete[] _str;
_str=NULL;
}
}
void Expand(size_t n){
if(n>_capacity){
char* tmp=new char[n+1];
strcpy(tmp,_str);
delete[] _str;
_str=tmp;
_capacity=n;
}
}
void PushBack(char ch){
if(_size>=_capacity){
Expand(2*_size);
}
_str[_size]=ch;
_str[_size+1]='\0';
++_size;
}
void Append(const char* str){//插入字符串
size_t len=strlen(str);
if(_size+len>=_capacity){
Expand(_size+len);
}
strcpy(_str+_size,str);
_size+=len;
}
void PopBack()
{
assert(_size);
_str[_size--]='\0';
--_size;
}
void Insert(size_t pos,char ch){
assert(pos<=_size);
if(_capacity==_size){
Expand(2*_capacity);
}
size_t end=_size;
while(end>=pos){
_str[end+1]=_str[end];
--end;
}
_str[pos]=ch;
++_size;
}
void Insert(size_t pos,const char* str){
assert(pos<=_size);
int len=strlen(str);
if(_size+len>_capacity){
Expand(_size+len);
}
for(int i=pos;i<_size;i++){
_str[i+len]=_str[i];
}
for(int j=0;j<len;j++){
_str[j+pos]=str[j];
}
}
void Erase(size_t pos,size_t n)
{
assert(pos<=_size);
if(pos==_size){
_str[_size-1]='\0';
--_size;
}else{
strcpy(_str+pos,_str+pos+n);
}
}
size_t Size()
{
return _size;
}
size_t Capacity()
{
return _capacity;
}
bool Empty()
{
return _size==0;
}
char& operator[](size_t pos){//读取某个位置的字符
return _str[pos];
}
size_t Find(char ch)
{
size_t count=0;
for(int i=0;i<_size;i++){
if(_str[i]==ch){
return count;
}
count++;
}
}
size_t Find(const char* str)
{
size_t count=0;
char* src=_str;
while(*src){
const char* dest=str;
while(*dest==*src){
dest++;
src++;
}
if(*dest=='\0'){
return count;
}
src++;
count++;
}
return size_t(-1);
}
String operator+(char ch)
{
String tmp(*this);
tmp.PushBack(ch);
return tmp;
}
String& operator+=(char ch){
this->PushBack(ch);
return *this;
}
//s1+=s2
String operator+=(const String& str){
*this+=str._str;//s._str是字符串,会去调用上面的operator+=
return *this;
}
String operator+(const char* str){
assert(str);
String tmp(*this);
tmp.Append(str);
return tmp;
}
String& operator+=(char* str){
this->Append(str);
return *this;
}
int _strcmp(const char* str1,const char* str2){
while(*str1&&*str2){
if(*str1>*str2){
return 1;
}else if(*str1<*str2){
return -1;
}else{
str1++;
str2++;
}
}
return 0;
}
//s1<s2
bool operator<(const String& s){
if((_strcmp(_str,s._str))==-1){
return true;
}else{
return false;
}
}
bool operator<=(const String& s)
{
if((_strcmp(_str,s._str))<=0){
return true;
}else{
return false;
}
}
bool operator>(const String& s)
{
if((_strcmp(_str,s._str))>0){
return true;
}else{
return false;
}
}
bool operator>=(const String& s)
{
if((_strcmp(_str,s._str))>=0){
return true;
}else{
return false;
}
}
//返回C形式字符串
char* c_str(){
return _str;
}
private:
char* _str;
size_t _size;
size_t _capacity;
};
void TestString(){
String s1("hello");
// cout<<s1.c_str()<<endl;
// s1.Insert(3,"花花");
// cout<<s1.c_str()<<endl;
// cout<<s1.Empty()<<endl;
// cout<<s1.Find("ol")<<endl;
}
int main(){
TestString();
}