• 【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] = '';
    	}
    	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] = '';
    	}
    	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;
    }

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


    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    springMVC-MyBatis-Mysql 环境下, 返回时间格式不是指定格式
    大话设计模式--第一章 简单工厂设计模式
    java编程思想第四版第十八章总结
    尚学堂-马士兵-专题-正则表达式
    张孝祥java高新技术 --- jkd1.5 新特性 -- 精华总结
    Python—文件进阶操作
    Python—文件读写操作
    Python—异常处理
    Python—网络抓包与解包(pcap、dpkt)
    Python—其它模块
  • 原文地址:https://www.cnblogs.com/ruan875417/p/4785416.html
Copyright © 2020-2023  润新知