【more effective c++读书笔记】【第5章】技术(5)——Reference counting(引用计数)(1)
一、非引用计数实现的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; }引用计数允许多个等值对象共享同一实值。此计数有两个动机:第一为了简化堆对象周边的簿记工作。第二是为了实现一种常识,所有等值对象共享同一实值,不仅节省内存,也使程序速度加快。
版权声明:本文为博主原创文章,未经博主允许不得转载。
posted on 2015-09-06 11:13 ruan875417 阅读(130) 评论(0) 编辑 收藏 举报