当前位置: 代码迷 >> 综合 >> 【more effective c++读书笔记】【第5章】技术(5)——Reference counting(引用计数)(1)
  详细解决方案

【more effective c++读书笔记】【第5章】技术(5)——Reference counting(引用计数)(1)

热度:18   发布时间:2023-12-21 17:56:23.0

一、非引用计数实现的String类

//String.h
#ifndef STRING_H
#define STRING_H
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>class String{
public:String(const char* initValue = nullptr);//构造函数String(const String& rhs);//拷贝构造函数~String();//析构函数String& operator=(const String& rhs);//拷贝赋值运算符String operator+(const String& rhs);//重载+运算符String operator+=(const String& rhs);//重载+=运算符bool operator==(const String& rhs);//重载==运算符char& operator[](size_t index);//重载[]运算符int getLength();//获取长度friend std::istream& operator>>(std::istream& is, const String& str);//重载>>运算符friend std::ostream& operator<<(std::ostream& os, const String& str);//重载<<运算符
private:char* data;
};
//构造函数
String::String(const char* initValue){if (initValue == nullptr){data = new char[1];data[0] = '\0';}else{data = new char[strlen(initValue) + 1];strcpy(data, initValue);}
}
//拷贝构造函数,要new一块新内存
String::String(const String& rhs){this->data = new char[strlen(rhs.data) + 1];strcpy(this->data, rhs.data);
}
//析构函数
String::~String(){delete[] data;data = nullptr;
}
//拷贝赋值运算符,要new一块新内存
String& String::operator=(const String& rhs){if (this == &rhs)return *this;delete[] data;data = new char[strlen(rhs.data) + 1];strcpy(data, rhs.data);return *this;
}
//重载+运算符
String String::operator+(const String& rhs){String newStr;if (rhs.data == nullptr)newStr = *this;else if (this->data == nullptr)newStr = rhs;else{newStr.data = new char[strlen(this->data) + strlen(rhs.data) + 1];strcpy(newStr.data, this->data);strcat(newStr.data, rhs.data);}return newStr;
}
//重载+=运算符
String String::operator+=(const String& rhs){if (rhs.data == nullptr)return *this;char* pTemp = new char[strlen(this->data) + strlen(rhs.data) + 1];strcpy(pTemp, this->data);strcat(pTemp, rhs.data);delete[] this->data;this->data = pTemp;return *this;
}
//重载==运算符
bool String::operator==(const String& rhs){return strcmp(this->data, rhs.data) == 0 ? true : false;
}
//重载[]运算符
char& String::operator[](size_t index){if (index<strlen(data))return data[index];
}
//获取长度
int String::getLength(){return strlen(data);
}
//重载>>运算符
std::istream& operator>>(std::istream& is, const String& str){is >> str.data;return is;
}
//重载<<运算符
std::ostream& operator<<(std::ostream& os, const String& str){os << str.data;return os;
}
#endif
//main.cpp 
#include"String.h"
using namespace std;int main(){String str1 = "hello";//调用构造函数String str2 = " world";//调用构造函数//调用重载+运算符String str3 = str1 + str2;cout << str3 << endl;//"hello world" 重载<<运算符//调用拷贝构造函数String str4 = str1;cout << str4 << endl;//"hello" 重载<<运算符//调用重载+=运算符str4 += str2;cout << str4 << endl;//"hello world" 重载<<运算符//调用重载==运算符if (str3 == str4)cout << "equal" << endl;//"equal" //调用拷贝赋值运算符str4 = str2;cout << str4 << endl;//" world" 重载<<运算符cout << str4[2] << endl;//'o'String str5;cin >> str5; //重载>>运算符cout << str5 << endl;//重载>>运算符system("pause");return 0;
}

上述例子实现的是用非引用计数实现的String类,缺点是浪费内存,因为在拷贝构造函数和拷贝赋值运算符内都会new出一块新内存。

二、引用计数实现的String类

//String.h
#ifndef STRING_H
#define STRING_H
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>class String{
public:String(const char* initValue = nullptr);//构造函数String(const String& rhs);//拷贝构造函数~String();//析构函数String& operator=(const String& rhs);//拷贝赋值运算符String operator+(const String& rhs);//重载+运算符String& operator+=(const String& rhs);//重载+=运算符bool operator==(const String& rhs);//重载==运算符const char& operator[](size_t index) const;//重载[]运算符,针对const Stringschar& operator[](size_t index);//重载[]运算符,针对non-const Stringsint getLength();//获取长度friend std::istream& operator>>(std::istream& is, const String& str);//重载>>运算符friend std::ostream& operator<<(std::ostream& os, const String& str);//重载<<运算符int getRefCount();//获取引用对象的个数
private:struct StringValue{int refCount;//引用计数char* data;StringValue(const char* initValue);//构造函数~StringValue();//析构函数};StringValue* value;
};
//StringValue类的构造函数
String::StringValue::StringValue(const char* initValue):refCount(1){if (initValue == nullptr){data = new char[1];data[0] = '\0';}else{data = new char[strlen(initValue) + 1];strcpy(data, initValue);}
}
//StringValue类的析构函数
String::StringValue::~StringValue(){delete[] data;data = nullptr;
}
//String类的构造函数
String::String(const char* initValue) :value(new StringValue(initValue)){}
//String类的拷贝构造函数
String::String(const String& rhs) : value(rhs.value){++value->refCount;//引用计数加1
}
//String类的析构函数
String::~String(){if (--value->refCount == 0){//析构时引用计数减1,当变为0时,没有指针指向该内存,销毁delete value;}
}
//String类的拷贝赋值运算符
String& String::operator=(const String& rhs){if (this->value == rhs.value) //自赋值return *this;//赋值时左操作数引用计数减1,当变为0时,没有指针指向该内存,销毁if (--value->refCount == 0)delete value;//不必开辟新内存空间,只要让指针指向同一块内存,并把该内存块的引用计数加1value = rhs.value;++value->refCount;return *this;
}
//String类的重载+运算符
String String::operator+(const String& rhs){return String(*this) += rhs;
}
//String类的重载+=运算符
String& String::operator+=(const String& rhs){//左操作数引用计数减1,当变为0时,没有指针指向该内存,销毁if (--value->refCount == 0)delete value;//右操作数为空if (rhs.value->data == nullptr){value = new StringValue(value->data);return *this;}	//左操作数为空if (this->value->data == nullptr){value = new StringValue(rhs.value->data);return *this;}//都不空char* pTemp = new char[strlen(this->value->data) + strlen(rhs.value->data) + 1];strcpy(pTemp, this->value->data);strcat(pTemp, rhs.value->data);value=new StringValue(pTemp);return *this;
}
//重载==运算符
bool String::operator==(const String& rhs){return strcmp(this->value->data, rhs.value->data) == 0 ? true : false;
}
//重载[]运算符,针对const Strings
const char& String::operator[](size_t index) const{if (index<strlen(value->data))return value->data[index];
}
//重载[]运算符,针对non-const Strings
char& String::operator[](size_t index){if (value->refCount>1){--value->refCount;value = new StringValue(value->data);}if (index<strlen(value->data))return value->data[index];
}
//获取长度
int String::getLength(){return strlen(this->value->data);
}
//重载>>运算符
std::istream& operator>>(std::istream& is, const String& str){is >> str.value->data;return is;
}
//重载<<运算符
std::ostream& operator<<(std::ostream& os, const String& str){os << str.value->data;return os;
}
//获取引用对象的个数
int String::getRefCount(){return value->refCount;
}#endif
//main.cpp
#include"String.h"
using namespace std;int main(){String str1("hello world");String str2 = str1;//调用拷贝构造函数String str3;//调用默认构造函数str3 = str2;//调用拷贝赋值运算符cout << "str1的引用计数是:" << str1.getRefCount() << endl; // 3cout << "str2的引用计数是:" << str2.getRefCount() << endl; // 3cout << "str3的引用计数是:" << str3.getRefCount() << endl; // 3str1[0] = 'H';//调用针对non-const Strings的重载[]运算符cout << str1 << endl; //"Hello world"cout << str2 << endl;//"hello world"cout << str3 << endl;//"hello world" cout << "str1的引用计数是:" << str1.getRefCount() << endl;//1cout << "str2的引用计数是:" << str2.getRefCount() << endl;//2cout << "str3的引用计数是:" << str3.getRefCount() << endl;//2String str4("hello");//调用构造函数String str5 = str4;//调用拷贝构造函数String str6 = " world";//调用构造函数str5 = str5+str6;//调用String类的重载+运算符,调用String类的拷贝赋值运算符cout << str4 << endl; //"hello"cout << str5 << endl; //"hello world"cout << str6 << endl; //" world"cout << "str4的引用计数是:" << str4.getRefCount() << endl;//1cout << "str5的引用计数是:" << str5.getRefCount() << endl;//1cout << "str6的引用计数是:" << str6.getRefCount() << endl;//1String str7 = str5;//调用拷贝构造函数String str8;//调用默认构造函数str8 = str7;//调用String类的拷贝赋值运算符cout << str7 << endl; //"hello world"cout << "str5的引用计数是:" << str5.getRefCount() << endl;//3cout << "str7的引用计数是:" << str7.getRefCount() << endl;//3cout << "str8的引用计数是:" << str8.getRefCount() << endl;//3str5 += str6;//调用String类的重载+=运算符cout << str5 << endl; //"hello world world"cout << str6 << endl; //" world"cout << str7 << endl; //"hello world"cout << str8 << endl; //"hello world"cout << "str5的引用计数是:" << str5.getRefCount() << endl; //1cout << "str6的引用计数是:" << str6.getRefCount() << endl;//1cout << "str7的引用计数是:" << str7.getRefCount() << endl;//2cout << "str8的引用计数是:" << str8.getRefCount() << endl;//2system("pause");return 0;
}

引用计数允许多个等值对象共享同一实值。此计数有两个动机:第一为了简化堆对象周边的簿记工作。第二是为了实现一种常识,所有等值对象共享同一实值,不仅节省内存,也使程序速度加快。


  相关解决方案