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造成的问题:两个不相干的字符串会相互影响,整个类在共享一个锁,安全性问题,向右挪过去。