就是将对象的指针拷贝过来,然后几个对象就使用同一块内存,释放时就会将一块内存释放多次,这就会引起程序崩溃(非法访问野指针)。
为了解决上述问题就引出了深拷贝。
当s1要用s2来拷贝的时候,就重新开一段和s1一样大的空间,并将值依次拷贝下来,析构时各自析构各自的空间,互不影响,同时对一个对象操作不会影响到另一个对象。
// 1.现代写法
// 2.传统写法
// 3.字符串增删查改
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
#include<assert.h>
using namespace std;
class String
{
private:
char* _str;
size_t _size;
size_t _capacity;
public:
String(const char* str)//不可以直接赋值,要先开辟一块空间将值拷贝进去在_str指向这块空间
:_str(new char[strlen(str) + 1])
{//多开一个‘\0’的空间
strcpy(_str, str);
_size = strlen(str);
_capacity = _size;
}
// String s2(s1)
//传统写法
String(const String& s)
:_str(new char[strlen(s._str) + 1])
,_size(strlen(s._str))
, _capacity(s._capacity)
{
strcpy(_str, s._str);
}
//现代写法
/*String(const String& s)
{
_size(strlen(s._str));
_capacity=_size;
String tmp(s._str);
swap(tmp, *this);
}*/
// s1 = s2
String& operator=(String s){
if (this != &s){
delete[]_str;
_str = new char(strlen(s._str) + 1);
strcpy(_str, s._str);
_size = strlen(s._str);
_capacity = _size;
}
return *this;
}
const char* c_str(){//相当于打印字符串
return _str;
}
void Expand(size_t n){
char* tmp = new char[n + 1];//每次多开一个字节
strcpy(tmp,_str);
delete[]_str;
_str= tmp;
tmp = NULL;
_capacity = n;
}
void PushBack(char ch){
if (_size >= _capacity){
Expand(2 * _capacity);
}
_str[_size] = ch;
_size++;
_capacity *= 2;
}
void PushBack(const char* str){
size_t len = strlen(str);
if (_size + len > _capacity){
Expand(len + _size);
}
strcpy(_str + _size, str);
_size += len;
}
void PopBack(){
assert(_size);
_str[_size - 1] = '\0';
_size--;
}
void PushFront(char ch){
if (_size >= _capacity){
Expand(2 * _capacity);
}
for (int i = _size; i >= 0; --i){//连同'\0'一起往后挪
_str[i + 1] = _str[i];
}
_str[0] = ch;
_size++;
_capacity *= 2;
}
void PushFront(const char* str){
size_t len = strlen(str);
if (_size + len >_capacity){
Expand(_size + len);
}
for (int i = _size; i >= 0; --i){
_str[i + len] = _str[i];
}
/*for (int j = 0; j< len; j++){
_str[j] = *str;
str++;
}*/
memcpy(_str, str, len);
_size += len;
_capacity += len;
}
void PopFront(){
strcpy(_str, _str + 1);
_size--;
}
void Insert(size_t pos, char ch){
assert(pos <= _size);
if (_size >=_capacity){
Expand(2 * _capacity);
}
for (int i = _size; i >= (int)pos; --i){
_str[i + 1] = _str[i];
}
_str[pos] = ch;
_size++;
_capacity *= 2;
}
void Insert(size_t pos, const char* str){
assert(pos <= _size);
size_t len = strlen(str);
if (_size + len > _capacity){
Expand(_size + len);
}
for (int i = _size; i >= (int)pos; --i){
_str[i + len] = _str[i];
}
for (int j = 0; j < len; j++){
_str[pos + j] = str[j];
}
_size += len;
_capacity += len;
}
void Erase(size_t pos, size_t n = 1){//从pos处删n个元素
assert(pos <= _size);
if (pos + n >= _size){
_str[pos] = '\0';
_size = pos;
}
else{
/*for (int i = pos; i < _size - n;i++){
_str[i] = _str[i + n];
}*/
strcpy(_str + pos, _str + pos + n);
}
_size -= n;
}
void Replace(char ch1, char ch2){//"change world h"-----ok
for (size_t i = 0; i < _size; i++){
if (_str[i] == ch1){
_str[i] = ch2;
}
}
}
void Replace(const char* sub1, const char* sub2){
size_t pos = Find(sub1);
Insert(pos, sub2);
}
char& operator[](size_t pos){
assert(pos < _size);
return _str[pos];
}
size_t Find(char ch){
for (int i = 0; i<_size; i++){
if (_str[i] == ch){
return i;
}
}
return size_t(-1);
}
size_t Find(const char* str){
assert(str);
int len = strlen(str);
int k = len;
if (_sizereturn size_t(-1);
}
int i = 0;
while (*_str){
if (*(_str + i) == *str){
int j = 0;
k = len;
while (k > 0){
if (*(_str + i + j) == *(str + j)){
j++;
k--;
}
else{
i++;
break;
}
}
if (k== 0){
return i;
}
else{
i++;
break;
}
}
i++;
}
return size_t(-1);
}
int mycmp(char* str1, const char* str2){
while (*str1&&*str2){
if (*str1 > *str2){
return 1;
}
else if (*str1 < *str2){
return -1;
}
else{
str1++;
str2++;
}
}
if (*str1 == '\0'&&*str2 == '\0'){
return 0;
}
else if (*str1){
return 1;
}
else
return -1;
}
bool operator>(String& s){
if (mycmp(_str, s._str) == 1){
return true;
}
return false;
}
bool operator>=(String& s){
return _str > s._str || _str == s._str;
}
bool operator<(String& s){
return !(_str >= s._str);
}
bool operator<=(String& s){
return !(_str>s._str);
}
bool operator==(String& s){
if (mycmp(_str, s._str) == 0){
return true;
}
return false;
}
bool operator!=(String& s){
return !(_str == s._str);
}
~String()
{
if (_str){
delete[]_str;
}
_str = NULL;
}
size_t Size(){
return _size;
}
};
//////////////////////////////测试代码//////////////////////////////////////////
void TestString()
{
//String s1("hello");
//String s2("hello world");
//cout << (s2 > s1) << endl;//1
//String s3("hello");
//cout << (s1 == s2) << endl;//0
//cout << (s1 == s3) << endl;//1
//cout << (s1
//cout << (s1 <= s2) << endl;//1
String s1("change world h");
/*char ch = 'h';
int ret = 0;
ret = s1.Find(ch);
cout << ret << endl;*/
//s1.Replace('h', 'g');
/*cout << s1.c_str() << endl;
size_t ret = s1.Find("ange");
cout << ret << endl;
s1.Replace("ange", "hahaha");
cout << s1.c_str() << endl;*/
s1.PushBack("!!!");
cout << s1.c_str() << endl;
s1.PopBack();
cout << s1.c_str() << endl;
s1.PushFront("welcome ");
cout << s1.c_str() << endl;
s1.PopFront();
s1.PopFront();
s1.PopFront();
cout << "头删三个字符:";
cout << s1.c_str() << endl;
}
int main(){
TestString();
system("pause");
return 0;
}
既然浅拷贝会涉及多个对象指向同一块空间,导致析构的时候同一块空间被释放多次,进而导致程序崩溃,所以引出了引用计数的浅拷贝,但是这种拷贝方式虽然能借助引用计数来记住有几个对象指向这块空间的,在析构之前先将引用计数减一下,如果是0的话,再析构,否则可以不做考虑,可是这种引用计数的浅拷贝仍存在弊端,就是在拷贝的时候,如果对象是一个个指针他只是单纯的将指针依次拷贝,这在后面对对象操作时又会有影响,综合考虑使用深拷贝,深拷贝就是要重新再开一块和原来对象同样大的空间,然后依次将数据拷贝到新空间中。不过我们看到深拷贝是要重新开空间,这样
开销会很大,既然采用深拷贝是为了解决改一个影响其他几个的问题,那么我们就可以只在修改的时候拷贝空间,所以就是我们的写时拷贝,综上所述,不仅要解决析构的时候同一块空间被析构多次,又要解决频繁的开空间,这就得说一说我们的引用计数的写时拷贝机制了
#include
#include
#include
#include
using namespace std;
class String
{
private:
char* _str;
size_t _size;
size_t _capacity;
int* RefCount;
public:
String(const char* str)
:_str(new char[strlen(str) + 1+4])
{
strcpy(_str+4, str);
_size = strlen(str);
_capacity = _size;
*RefCount=1;
}
// String s2(s1)
String(const String& s)
{
_size(strlen(s._str));
_capacity=_size;
String tmp(s._str);
swap(tmp, *this);
*RefCount++;
}
// s1 = s2
String& operator=(String s){
if (this != &s){
if(--*RefCount){
strcpy(_str, s._str);
_size = strlen(s._str);
_capacity = _size;
}
delete[](_str-4);
_str = new char(strlen(s._str) + 1);
strcpy(_str, s._str);
_size = strlen(s._str);
_capacity = _size;
}
return *this;
}
~String(){
if(*RefCount==1){
delete[] _str-4;
}
else{
*RefCount--;
}
}
};