当前位置 博文首页 > Foreordination_的博客:模拟实现C++STL中的string类

    Foreordination_的博客:模拟实现C++STL中的string类

    作者:[db:作者] 时间:2021-08-07 22:14

    ? ? ? ?在C++中的字符串有C语言继承过来的char* 型的,还有就是C++STL中的string型的了。

    ? ? ? ?C++中的string类在实现的过程中会遇到一些特别的地方。

    比如:深浅拷贝、写时拷贝、引用计数等一些概念

    浅拷贝:
    ? ? ? ?默认的拷贝构造函数(值拷贝)。会出现两个指针维护同一块空间的问题,可能会一个指针释放空间导致另一个指针访问非法空间。
    深拷贝:
    ? ? ? 自己构造拷贝构造函数,即自己开辟新空间再用memcpy进行值拷贝,用指针维护新开辟的空间
    写时拷贝:
    ? ? ? 在浅拷贝的基础上增加引用计数,若要修改同一块空间时,再开辟新空间并进行值拷贝
    ? ? ? 写时拷贝即实现operator[],缺点是用[]读的时候也进行拷贝


    深浅拷贝的应用:
    VS的string:用深拷贝实现。
    Linux中的string:用带引用计数的浅拷贝实现,operator[]时进行写时拷贝


    注:STL库中的string类有一个Buffer:
    小于16个字符的string以空间换时间
    大于16个字节的存在_ptr指针指向的另外空间

    string类源码:

    #define _CRT_SECURE_NO_WARNINGS
    #include<iostream>
    #include<cassert>
    using namespace std;
    //相同字符串指向同一块空间,用一个引用计数来统计该字符串被引用的次数,并且增加了写时拷贝
    class String
    {
    	friend ostream& operator<<(ostream& os, const String& s);
    public:
    	//String()
    	//	:_str(new char[1])
    	//	, _refCount(new int(1));
    	//{
    	//	_str[0] = '\0';
    	//}
    	String(const char *str = "")     //默认字符串为空字符串
    		:_str(new char[strlen(str) + 1])
    		, _refCount(new int(1))
    	{
    		strcpy(_str, str);
    		cout << "String(const char *str)" << endl;
    	}
    	
    	String(String& s)  //拷贝构造函数
    		:_str(s._str)     
    		, _refCount(s._refCount)
    	{
    		++(*_refCount);
    	}
    	//传统的写法(s1=s2)
    	String& operator=(const String& s)
    	{
    		//1、s1和s2指向同一块空间(不处理)
    		//2、减减s1指向空间的引用计数,若s1是最后一块管理对象,则释放s1
    		if (_str != s._str)
    		{
    			this->Release();
    
    			this->_str = s._str;
    			this->_refCount = s._refCount;
    			++(*_refCount);
    		}
    		return *this;
    	}
    	//现代的写法
    	String& operator=(String s)   //拷贝s时引用计数已经加1
    	{
    		swap(_str, s._str);
    		swap(_refCount, s._refCount);
    		return *this;
    	}
    	void Release()
    	{
    		if (--(*_refCount) == 0)
    		{
    			cout << "delete" << endl;
    			delete[] _str;
    			delete _refCount;
    		}
    	}
    	//String* this
    	char& operator[](size_t index)
    	{
    		//写时拷贝
    		CopyOnWrite();  //缺点:读的时候也会进行拷贝
    
    		assert(index < strlen(_str));
    		return _str[index];
    	}
    
    	//const String* this
    	const char& operator[](size_t index) const   //常成员函数,当访问常成员变量时调用
    	{
    		assert(index < strlen(_str));
    		return _str[index];
    	}
    
    	void CopyOnWrite()
    	{
    		//引用计数大于1时需要进行拷贝
    		if ((*_refCount)>1)
    		{
    			char* tmp = new char[strlen(_str) + 1];
    			strcpy(tmp, _str);
    			--(*_refCount);
    
    			_refCount = new int(1);
    			_str = tmp;
    		}
    	}
    	
    	~String()
    	{
    		Release();
    	}
    
    	char* GetStr()
    	{
    		return _str;
    	}
    private:
    	char* _str;
    	int* _refCount;   //引用计数的指针
    };
    
    ostream& operator<<(ostream& os, const String& s)   //重载string的输出符号
    {
    	os << s._str;
    	return os;
    }
    int main()
    {
    	const String str1("123456");
    	String str2="123";
    	String str3;
    	//str2 = str1;
    	str3 = str2;
    
    	String str4("abcdef");
    	String str5(str4);
    
    	cout << str1[3] << endl;
    	cout << str2 << endl;
    	cout << str3 << endl;
    
    	cout << str4 << endl;
    	cout << str5 << endl;
    	return 0;
    }



    cs