C++:mstring类的拷贝以及其他成员方法

10_26
1.mstring.h

#ifndef MSTRING_H
#define MSTRING_H
#include<iostream>
#include<mutex>
using namespace std;


#define MSTRING_MORE_SIZE sizeof(int)
#define DEFEALT_LEN (10+MSTRING_MORE_SIZE)



class Mstring
{
    
    
public:
	Mstring(const char* str = NULL);
	Mstring(const Mstring& src);
	Mstring& operator=(const Mstring& src);
	~Mstring();

	void push_back(char c);
	void pop_back();
	char back()const;
	char front()const;
	bool empty()const;
	int size()const;

	Mstring operator+(const Mstring& str)const;
	char& operator[](int pos);
	char operator[](int pos)const;

	friend ostream& operator<<(ostream& out, const Mstring& src);
	friend istream& operator>>(istream& in, Mstring& src);
private:
	bool full()const;
	void revert();
	void init_num();
	int& get_num();
	int get_num()const;
	const char* get_str_begin()const;
	char* get_str_begin();
	void write_copy();
	int down_num();//引用计数-1
	int up_num();//引用计数+1


	char* _str;//能否直接使用浅拷贝------怎么加引用计数
	int _len;//当前空间总长度
	int _val_len;//已经占用的长度,实际数据数量
	static mutex* _lock;
};

#endif

mstring.cpp

#include"mstring.h"

mutex* Mstring::_lock = new mutex();

Mstring::Mstring(const char* str)
{
    
    
	if (NULL == str)
	{
    
    
		_len = DEFEALT_LEN;
		_val_len = 0;
		_str = new char[_len];
		memset(_str, 0, _len);
		init_num();
		return;
	}

	_val_len = strlen(str);

	//加上引用计数占的空间
	_len = _val_len + 1 + MSTRING_MORE_SIZE;
	_str = new char[_len];
	memset(_str, 0, _len);

	for (int i = 0; i < _val_len; i++)
	{
    
    
		get_str_begin()[i] = str[i];
	}
	init_num();
}

Mstring::Mstring(const Mstring& src)
{
    
    
	_val_len = src._val_len;
	_len = src._len;
	_str = src._str;
	//让引用计数+1
	up_num();

	/*
	_val_len = strlen(src._str);
	_len = _val_len + 1;
	_str = new char[_len];
	memset(_str, 0, _len);

	for (int i = 0; i < _val_len; i++)
	{
		_str[i] = src._str[i];
	}
	*/
}

Mstring& Mstring::operator=(const Mstring& src)
{
    
    
	if (&src == this)
	{
    
    
		return *this;
	}
	_val_len = src._val_len;
	_len = src._len;
	_str = src._str;
	up_num();

	return *this;

	/*
	if (&src == this)
	{
		return *this;
	}

	delete[]_str;

	_val_len = strlen(src._str);
	_len = _val_len + 1;
	_str = new char[_len];
	memset(_str, 0, _len);

	for (int i = 0; i < _val_len; i++)
	{
		_str[i] = src._str[i];
	}
	return *this;
	*/
}

Mstring::~Mstring()
{
    
    
	//将引用计数-1
	down_num();

	//查看当前是否还有人引用
	if (0 == get_num())
	{
    
    
		delete[]_str;
	}
}

void Mstring::push_back(char c)
{
    
    
	//判断是否一个人独有
	if (get_num() > 1)
	{
    
    
		//写时拷贝,给分配独有的空间
		write_copy();
	}

	if (full())
	{
    
    
		revert();
	}

	get_str_begin()[_val_len] = c;
	_val_len++;
}

void Mstring::pop_back()
{
    
    
	if (get_num() > 1)
	{
    
    
		write_copy();
	}

	if (empty())
	{
    
    
		return;
	}

	_val_len--;
}

char Mstring::back()const//只能访问常方法
{
    
    
	if (empty())
	{
    
    
		return 0;
	}

	return get_str_begin()[_val_len - 1];
}

char Mstring::front()const
{
    
    
	if (empty())
	{
    
    
		return 0;
	}

	return get_str_begin()[0];
}

bool Mstring::empty()const
{
    
    
	return _val_len == 0;
}

Mstring Mstring::operator+(const Mstring& str)const
{
    
    
	char* p;
	int len = _val_len + str._val_len + 1;
	p = new char[len];
	memset(p, 0, len);

	//进行数据拷贝-----将两个字符串的数据拼接起来
	int i = 0;
	for (; i < _val_len; i++)
	{
    
    
		p[i] = get_str_begin()[i];//从字符串开始的位置拷贝,要减去引用计数器所占字节
	}

	for (int j = 0; j < str._val_len; j++, i++)
	{
    
    
		p[i] = str.get_str_begin()[j];
	}

	return p;
}

char& Mstring::operator[](int pos)//引用中括号运算符重载
{
    
    
	if (get_num() > 1)
	{
    
    
		write_copy();
	}
	return  get_str_begin()[pos];
}

char Mstring::operator[](int pos)const//值传递中括号运算符重载
{
    
    
	return  get_str_begin()[pos];
}

bool Mstring::full()const
{
    
    
	return _val_len == _len - 1 - MSTRING_MORE_SIZE;//减去宏(即引用计数器长度)
}

void Mstring::revert()
{
    
    
	if (get_num() > 1)
	{
    
    
		write_copy();
	}

	_len = _len << 1;

	char* p = new char[_len];
	memset(p, 0, _len);

	for(int i = 0;i<_val_len+MSTRING_MORE_SIZE;i++)
	{
    
    
		p[i] = _str[i];
	}

	if (down_num() == 0)
	{
    
    
		delete[]_str;
	}

	_str = p;
}

int Mstring::size()const
{
    
    
	return _val_len;
}

//初始化引用计数
void Mstring::init_num()
{
    
    
	get_num() = 1;
}

//获取引用计数
int& Mstring::get_num()
{
    
    
	return *((int*)_str);
}

//引用计数-1
int Mstring::down_num()
{
    
    
	_lock->lock();
	--get_num();
	_lock->unlock();
	return get_num();
}

//引用计数+1
int Mstring::up_num()
{
    
    
	//get_lock()->lock();
	_lock->lock();
	++get_num();
	_lock->unlock();

	return get_num();
}


//获取引用计数
int Mstring::get_num()const
{
    
    
	return *((int*)_str);
}

//获取字符串的开头指针
char* Mstring::get_str_begin()
{
    
    
	return _str + MSTRING_MORE_SIZE;
}

//获取字符串的开头指针
const char* Mstring::get_str_begin()const
{
    
    
	return _str + MSTRING_MORE_SIZE;
}

//写时拷贝
void Mstring::write_copy()
{
    
    
	char* p = new char[_len];

	//将所有的数据全部拷贝过来
	for (int i = 0; i < _len; i++)
	{
    
    
		p[i] = _str[i];
	}

	//改变原来指向的内存的引用计数
	if (0 == down_num())
	{
    
    
		delete[]_str;
	}

	//将当前引用计数改为1
	_str = p;
	init_num();
}

ostream& operator<<(ostream& out, const Mstring& src)
{
    
    
	for (int i = 0; i < src.size(); i++)
	{
    
    
		out << src.get_str_begin()[i];
	}
	out << "     :::::num:::" << src.get_num();
	out << endl;
	return out;
}

istream& operator>>(istream& in, Mstring& src)
{
    
    
	if (src.get_num() > 1)
	{
    
    
		src.write_copy();
	}
	//in>>src.str; 错误写法,有可能会占满内存导致不能释放

	char tmp[1024];
	in >> tmp;
	
	src = tmp;//tmp构造临时对象,用构造的临时对象作等号运算符的重载
	return in;
}


main(msrting).cpp

#include"mstring.h"


int main()
{
    
    
	Mstring s1 = "123456";

	Mstring s2 = s1;//拷贝构造----深拷贝

	Mstring s3;
	s3 = s1;//等号运算符重载-----深拷贝

	Mstring* ps = new Mstring(s1);

	//cout << s1 << endl;
	//cout << s2 << endl;
	//cout << s3 << endl;
	//s1[4] = 'y';
	//s3.push_back('k');
	//cin >> s1;

	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	cout << *ps << endl;

	delete ps;

	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	//cout << *ps << endl;

	return 0;
}


/*
1.将引用计数版本实现出来
2.将mutex锁加入 -----   选做



3.刷题没交的赶紧交


*/

写时拷贝

当多个对象同时拥有一块内存的时候,每个对象都只有读取的权限,如果某个对象需要修改内存,就需要给它单独拷贝一份
析构反复释放一块内存会造成内存泄露,解决方法:加一个引用计数
写时拷贝:就是在需要修改的这块空间的内容时才分配一块空间。

map表

map<char*,int> _num_map;
//查找有序,根据键排序
//键和值构成的键值对,查找速度非常快

引用计数执行加减操作,在多线程里面会出现问题,所以要使用mutex
使用静态mutex造成的问题:两个不相干的字符串会相互影响,整个类在共享一个锁,安全性问题,向右挪过去。

猜你喜欢

转载自blog.csdn.net/qq_48580892/article/details/121000521