//
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
//管理字符串
class String
{
public:
String() :_pStr(new char('\0'))
{}
String(const char* pStr)
{
if (NULL == pStr)
_pStr = new char('\0');
else
{
_pStr = new char(strlen(pStr) + 1);
strcpy(_pStr, pStr);
}
}
~String()
{
if (_pStr)
{
delete[] _pStr;
_pStr = NULL;
}
}
private:
char* _pStr;
};
void Test()
{
char* p = "hello";
String s1;
String s2(p);
String s3("hello");
}
int main()
{
Test();
system("pause");
return 0;
}
析构函数:弥补了销毁时使用delete[]还是delet
content:
<1.0> //管理字符串---》反例
<2.0>//浅拷贝
<3.0>//深拷贝-->普通版
<4.0>//深拷贝-->简洁版
<5.0>//浅拷贝(引用计数版)_count普通类成员变量
<6.0>//浅拷贝(引用计数版)_count static类成员变量
<7.0>//浅拷贝(引用计数版)int* _count 类成员变量
<8.0>浅拷贝(引用计数版)(模仿new)
<1.0>//管理字符串---》反例
代码一:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class String
{
public:
String(const char* pStr = " ")
{
if (NULL == pStr)
{
_pStr = new char[1];
*_pStr = '\0';
}
else
{
_pStr = new char[strlen(pStr) + 1];
strcpy(_pStr, pStr);
}
}
~String()
{
if (_pStr)
{
delete[] _pStr;
_pStr = NULL;
}
}
private:
char* _pStr;
};
void Test()
{
String s1("hello");
String s2;
String s3(NULL);
String s4(s3);
}
int main()
{
Test();
system("pause");
return 0;
}
结果如下:
由上图可以看出来:s3和s4共用同一空间,所以上面代码只是对字符串的表面操作内部却没有动。
<2.0>//浅拷贝:
代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class String
{
public:
String(const char* pStr = " ")
{
if (NULL == pStr)
{
_pStr = new char[1];
*_pStr = '\0';
}
else
{
_pStr = new char[strlen(pStr) + 1];
strcpy(_pStr, pStr);
}
}
String(const String& s) :_pStr(s._pStr)
{}
String& operator=(const String& s) //
{
if (this != &s)
{
_pStr = s._pStr;
}
else
return *this;
}
~String()
{
if (_pStr)
{
delete[] _pStr;
_pStr = NULL;
}
}
private:
char* _pStr;
};
void Test()
{
String s1("hello");
String s2;
String s3(NULL);
String s4(s3);
}
int main()
{
Test();
system("pause");
return 0;
}
存在的问题:
1.0
2.0
<3.0>//深拷贝-->普通版:
代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class String
{
public:
String(const char* pStr = " ")
{
if (NULL == pStr)
{
_pStr = new char[1];
*_pStr = '\0';
}
else
{
_pStr = new char[strlen(pStr) + 1];
strcpy(_pStr, pStr);
}
}
//拷贝构造函数一:
String(const String& s) :_pStr(new char[strlen(s._pStr)+1])
{
strcpy(_pStr,s._pStr);
}
//拷贝构造函数二:
//String(const String& s)//缺点:_pStr指向不明,野指针,非手动开辟,手动释放,出错。
//{
// if (NULL != _pStr)
// delete[] _pStr;
// _pStr = new char[strlen(s._pStr) + 1];
// strcpy(_pStr, s._pStr);
//}
//赋值运算符重载: 1.0申请新空间,拷贝元素
// 2.0释放旧空间
// 3.0使用新空间(更改指向)
//赋值运算符重载一:
String& operator=(const String& s)
{
if (this != &s)
{
char* pTemp = new char[strlen(s._pStr) + 1];
strcpy(pTemp, s._pStr);
delete[] _pStr;
_pStr = pTemp;
}
else
return *this;
}
//赋值运算符重载一:
/*String& operator=(const String& s) //缺点:直接释放空间,万一下一步开辟失败
{ //也找不到原来指向的空间。
if (this != &s)
{
delete[] _pStr;
_pStr = new char[strlen(s._pStr) + 1];
strcpy(_pStr, s._pStr);
}
else
return *this;
}*/
~String()
{
if (_pStr)
{
delete[] _pStr;
_pStr = NULL;
}
}
private:
char* _pStr;
};
void Test()
{
String s1("hello");
String s2;
String s3(NULL);
String s4(s3);
}
int main()
{
Test();
system("pause");
return 0;
}
<4.0>//深拷贝(简洁版)
代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class String
{
public:
String(const char* pStr = " ")
{
if (NULL == pStr)
{
_pStr = new char[1];
*_pStr = '\0';
}
else
{
_pStr = new char[strlen(pStr) + 1];
strcpy(_pStr, pStr);
}
}
//拷贝构造函数一:
/*String(const String& s) //不足:得释放StrTemp._pStr(它不为NULL时)
{ //构造新对象时,_pStr指向的空间不明确没有给它手动开辟空间交换后。
String StrTemp(s._pStr); //直接调析构函数去释放StrTemp._pStr存在内存泄漏
swap(_pStr,StrTemp._pStr);
}*/
//拷贝构造函数二:
//String(const String& s) //缺点:申请了空间未用
//{
// _pStr = new char[];
// String StrTemp(s, _pStr);
// swap(_pStr, StrTemp._pStr);
//}
//拷贝构造函数三:
String(const String& s) :_pStr(NULL) //优点:不用释放StrTemp._pStr(它为NULL)
{
String StrTemp(s._pStr);
swap(_pStr, StrTemp._pStr);
}
//赋值运算符重载一:
String& operator=(const String& s)
{
if (this != &s)
{
String StrTemp(s._pStr); //左侧调用构造函数 String StrTemp(s)调用拷贝构造函数;
//调拷贝构造函数又得String StrTemp(s._pStr);代码冗余
swap(_pStr, StrTemp._pStr);
}
return *this;
}
//赋值运算符重载二:
//String& operator=(const String& s)//无法避免自己给自己赋值的情况
//{
// String StrTemp(s._pStr);
// swap(_pStr, StrTemp._pStr);
// return *this;
//}
//赋值运算符重载三:
//String& operator=(const String& s)//无法避免自己给自己赋值的情况,赋值完成后源的内容也变了
//{ //违背了赋值的初衷:a=b,a的内容变,b内容不变
// swap(_pStr,s._pStr);
// return *this;
//}
~String()
{
if (_pStr)
{
delete[] _pStr;
_pStr = NULL;
}
}
private:
char* _pStr;
};
void Test()
{
String s1("hello");
String s2;
String s3=s1;
String s4(s3);
}
int main()
{
Test();
system("pause");
return 0;
}
监视:
<5.0>//浅拷贝(引用计数版)_count普通类成员变量
代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class String
{
public:
String(const char* pStr = " ")
{
if (NULL == pStr)
{
_pStr = new char[1];
*_pStr = '\0';
}
else
{
_pStr = new char[strlen(pStr) + 1];
strcpy(_pStr, pStr);
}
_count = 1;
}
String(const String& s) :_pStr(s._pStr), _count(++s._count)
{}
String& operator=(const String& s)
{
if (this != &s)
{
String StrTemp(s._pStr);
swap(_pStr, StrTemp._pStr);
swap(_count, StrTemp._count);
}
return *this;
}
~String()
{
if (_pStr&&--_count==0)
{
delete[] _pStr;
_pStr = NULL;
}
}
private:
char* _pStr;
mutable int _count;
};
void Test()
{
String s1("hello");
String s2;
String s3;
s3= s1;
String s4(s3);
}
int main()
{
Test();
system("pause");
return 0;
}
第一次调析构函数
第二次调析构函数
清空s4时s3与s4共用 同一片空间,s3._count-1之后明显s3没有减一,所以之后这空间还会被销毁一次,内存泄露。
<6.0>//浅拷贝(引用计数版)_count static类成员变量
代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class String
{
public:
String(const char* pStr = " ")
{
if (NULL == pStr)
{
_pStr = new char[1];
*_pStr = '\0';
}
else
{
_pStr = new char[strlen(pStr) + 1];
strcpy(_pStr, pStr);
}
_count = 1;
}
String(const String& s) :_pStr(s._pStr)
{
_count = s._count;
_count++;
}
String& operator=(const String& s)
{
if (this != &s)
{
String StrTemp(s._pStr);
swap(_pStr, StrTemp._pStr);
swap(_count, StrTemp._count);
}
return *this;
}
~String()
{
if (_pStr&&--_count == 0)
{
delete[] _pStr;
_pStr = NULL;
}
}
private:
char* _pStr;
static int _count;
};
int String::_count = 0;
void Test()
{
String s1("hello");
String s2(s1);
String s3;
}
int main()
{
Test();
system("pause");
return 0;
}
String s1("hello");结果:
String s2(s1);结果:
String s3;结果:
这说明了将count设置为static型成员变量一旦构造新的类成员就会把count置为1,。与预期结果不符。
<7.0>//浅拷贝(引用计数版)int* _count 类成员变量
代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class String
{
public:
String(const char* pStr = " ") :_count(new int[1])
{
if (NULL == pStr)
{
_pStr = new char[1];
*_pStr = '\0';
}
else
{
_pStr = new char[strlen(pStr) + 1];
strcpy(_pStr, pStr);
}
*_count = 1;
}
String(const String& s) :_pStr(s._pStr)
{
_count = s._count;
(*_count)++;
}
String& operator=(const String& s)
{
if (_pStr != s._pStr) //避免:String s2(s1); String; s2=s1;的情况发生。
{
if (_pStr && 0 == --*_count)
{
delete[] _pStr;
delete[] _count;
}
_pStr = s._pStr;
++*(s._count);
_count = s._count;
}
return *this;
}
~String()
{
if (_pStr&&--(*_count) == 0)
{
delete[] _pStr;
_pStr = NULL;
delete[] _count;
_count == NULL;
}
}
private:
char* _pStr;
int* _count;
};
void Test()
{
String s1("hello");
String s2(s1);
String s3;
String s4(s3);
s3 = s2;
}
int main()
{
Test();
system("pause");
return 0;
}
结果:
缺点:需要维护两块空间(一大一小)
<8.0>浅拷贝(引用计数版)(模仿new)
代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class String
{
public:
String(const char* pStr = " ")
{
if (NULL == pStr)
{
_pStr = new char[1+4];
_pStr += 4;
*_pStr = '\0';
}
else
{
_pStr = new char[strlen(pStr) + 1+4];
_pStr += 4;
strcpy(_pStr, pStr);
}
GetRef() = 1;
}
String(const String& s) :_pStr(s._pStr)
{
GetRef()++;
}
String& operator=(const String& s)
{
if (_pStr != s._pStr) //避免:String s2(s1); String; s2=s1;的情况发生。
{
Release();
_pStr = s._pStr;
++GetRef();
}
return *this;
}
char& operator[](size_t index)
{
if (GetRef() > 1)
{
char* pTemp = new char[strlen(_pStr) + 1 + 4];
*(int*)pTemp = 1;
pTemp += 4;
strcpy(pTemp, _pStr);
--GetRef();
_pStr = pTemp;
}
return _pStr[index];
}
const char& operator[](size_t index) const
{
return _pStr[index];
}
friend ostream& operator<<(ostream& _cout, const String& c);
~String()
{
Release();
}
private:
char* _pStr;
int& GetRef()
{
return *((int*)_pStr - 1);
}
void Release()
{
if (_pStr && 0 == --GetRef())
{
_pStr -= 4;
delete[] _pStr;
_pStr = NULL;
}
}
};
ostream& operator<<(ostream& _cout, const String& c)
{
_cout << c._pStr;
return _cout;
}
void Test()
{
String s1("hello");
String s2(s1);
String s3;
String s4(s3);
s3 = s2;
s1[2] = 'o';
cout<<s1<< endl;
}
int main()
{
Test();
system("pause");
return 0;
}
结果:
总结:
1. 浅拷贝:也称位拷贝,编译器只是直接将指针的值拷贝过来,当多个对象共用同一块内存,当一
个对象将这块内存释放掉之后,另一些对象不知道该块空间已经还给了系统,以为还有效,所以
在对这段内存进行操作的时候,发生了访问违规。
2.写时拷贝--Copy On Write。