本篇博客模拟实现一个String类,使用深拷贝的传统与现代写法。
深拷贝:重新开辟空间,将原来的空间拷贝过来,再把值复制过来,
此种方法两个对象指向不同空间,析构时析构各自的数据块,不会造成内存泄露问题。(稍后在代码中解释)
传统写法
思路:
使用传统写法:即老实人的写法。
构造/拷贝构造/赋值运算符重载函数`先开辟空间再直接复制`
析构函数`如果_str!=NULL;释放空间,并将_str置为空,防止内存泄露`,所谓内存泄漏实际上丢失的是指针而非内存。
代码实现:
#pragma once
//传统写法
class String
{
public:
//构造函数
String(char* str)
:_str(new char[strlen(str) + 1])//开辟空间
{
strcpy(_str, str);
}
//拷贝构造函数
//s2(s1)
String(const String &s)
{
this->_str = new char[strlen(s._str) + 1];
strcpy(_str, s._str);
}
//赋值运算符重载
//s2=s1
//s1=s1
String& operator=(const String& s)
{
if (this != &s)//避免自身赋值
{
delete[] _str;
_str = new char[strlen(s._str) + 1];
strcpy(_str, s._str);
}
return *this;
}
//打印字符串
const char* c_str()
{
return _str;
}
//析构函数
~String()
{
if (_str)
{
delete[] _str;
_str = NULL;
}
}
private:
char *_str;
};
//测试传统写法
void Test1()
{
String s1 = "Just Right";
String s2(s1);//调用拷贝构造函数,对象未存在
cout << "s1:"<<s1.c_str() << endl;
cout << "s2:" << s2.c_str() << endl;
String s3("hello world");
s1 = s3;//调用赋值运算符重载,对象已存在
cout << "s1:" << s1.c_str() << endl;
cout << "s3:" << s3.c_str() << endl;
}
结果为:
现代写法
思路:不开空间,借助构造函数实现
//现代写法
class String
{
public:
String(char *str)
:_str(new char[strlen(str)+1])
{
strcpy(_str, str);
}
//s2(s1)
String(const String& s)
:_str(NULL)
{
String tmp(s._str);//调用构造函数
swap(_str, tmp._str);
}
//s2=s1
String& operator=(const String& s)
{
if (this != &s)
{
String tmp(s._str);//调用构造函数
swap(_str, tmp._str);
}
return *this;
}
~String()
{
if (_str)
{
delete[] _str;
_str = NULL;
}
}
const char* c_str()
{
return _str;
}
private:
char *_str;
};
void Test2()
{
String s1 = "hello world";
String s2(s1);//调用拷贝构造函数,对象未存在
cout << "s1:" << s1.c_str() << endl;
cout << "s2:" << s2.c_str() << endl;
String s3("1234");
s1 = s3;//调用赋值运算符重载,对象已存在
cout << "s1:" << s1.c_str() << endl;
cout << "s3:" << s3.c_str() << endl;
}
分析:
结果:
由上图发现s1与s2指向不同空间