您的位置:首页 > 编程语言 > C语言/C++

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

2015-09-06 11:13 375 查看
一、非引用计数实现的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 Strings
char& operator[](size_t index);//重载[]运算符,针对non-const Strings
int 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;
//不必开辟新内存空间,只要让指针指向同一块内存,并把该内存块的引用计数加1
value = 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; // 3
cout << "str2的引用计数是:" << str2.getRefCount() << endl; // 3
cout << "str3的引用计数是:" << str3.getRefCount() << endl; // 3

str1[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;//1
cout << "str2的引用计数是:" << str2.getRefCount() << endl;//2
cout << "str3的引用计数是:" << str3.getRefCount() << endl;//2

String 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;//1
cout << "str5的引用计数是:" << str5.getRefCount() << endl;//1
cout << "str6的引用计数是:" << str6.getRefCount() << endl;//1

String str7 = str5;//调用拷贝构造函数
String str8;//调用默认构造函数
str8 = str7;//调用String类的拷贝赋值运算符
cout << str7 << endl; //"hello world"
cout << "str5的引用计数是:" << str5.getRefCount() << endl;//3
cout << "str7的引用计数是:" << str7.getRefCount() << endl;//3
cout << "str8的引用计数是:" << str8.getRefCount() << endl;//3

str5 += 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; //1
cout << "str6的引用计数是:" << str6.getRefCount() << endl;//1
cout << "str7的引用计数是:" << str7.getRefCount() << endl;//2
cout << "str8的引用计数是:" << str8.getRefCount() << endl;//2

system("pause");
return 0;
}


引用计数允许多个等值对象共享同一实值。此计数有两个动机:第一为了简化堆对象周边的簿记工作。第二是为了实现一种常识,所有等值对象共享同一实值,不仅节省内存,也使程序速度加快。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: