-
namespace A
{
class string
{
public:
//迭代器
typedef char* iterator;//string里的迭代器本质指针,以后迭代器就不一定是指针了
typedef const char* const_iterator;//const类型的迭代器
const_iterator begin()const
{
return _str;
}
iterator begin()
{
return _str;
}
iterator end()const
{
return _str + _size;
}
//构造
string(const char* s = " ")
:_size(strlen(s))
,_capacity(strlen(s))
,_str(new char[strlen(s)+1])
{
strcpy(_str, s);
}
void swap(string& s) //这个是A::string里的swap
{
::swap(_size, s._size); //这个调用的是全局的swap
::swap(_capacity, s._capacity);
::swap(_str, s._str);
}
//拷贝构造
/*string (const string& b)
:_str(new char[strlen(b._str) + 1])
{
strcpy(_str, b._str);
}*/
string(const string& s)
:_str(nullptr) //这里必须初始化
{
string temp(s._str);//可能是这的问题
swap(temp);
//swap(_size, temp._size);//这里为啥不能用s.,因为参数是const类型的
//swap(_capacity, temp._capacity);
//swap(_str, temp._str);
//return *this;
}
//赋值运算符重载=
string& operator=(string s)
{
//swap(_size, s._size);
//swap(_capacity, s._capacity);
//swap(_str, s._str);
swap(s);
return *this;
}
//传统的=
//string& operator=(const string& b)
//{
// if (this != &b)
// {
// delete[]this->_str;//先判断赋值双方是不是一个
// _str = new char[strlen(b._str) + 1];
// strcpy(_str, b._str);
// }
// return *this;
//}
//析构函数
~string()
{
delete[] _str;
_str = nullptr;
_size = 0;
_capacity = 0;
}
//扩容
//开有效元素的个数并填充扩size
void resize(size_t size,char c='\0')
{
if (size < _size)
{
_str[size] = '\0';
_size = size;
}
else
{
if (size > _capacity)
{
reserve(size);
}
for (int i = _size; i < size; i++)
{
_str[i] = c;
}
_str[size] = '\0';
_size = size;
}
}
//单纯扩容扩capacity
void reserve(size_t capacity)
{
if (capacity > _capacity)
{
char* temp = new char[capacity+1];
strncpy(temp, _str,_size+1); //有效字符包含\0,拷贝的是字符,如果字符中间有\0,就拷不进去
strcpy(temp, _str); //用这个如果有效字符是\0考不下来,但是_size已经增加了,所以中间是随机值
delete[]_str;
_str = temp;
_capacity = capacity;
}
}
//曾
void push_back(char c)
{
if (_size == _capacity)
{
reserve(_capacity * 2);
}
_str[_size] = c;
_str[_size + 1] = '\0';
_size++;
}
void append(const char* str)
{
int len = _size + strlen(str)+1; //这个是擦边扩容,扩的刚好方下有效字符串,但是容量没有\0的位置,加一个\0的位置
if (len > _capacity) //strlen是错的,如果有效字符包含\0,就出错
{
reserve(len);
}
strcpy(_str + _size, str);
_size = len;
}
string operator+=(char c)
{
push_back(c);
return *this;
}
string operator+=(const char* str)
{
append(str);
return *this;
}
string& insert(size_t pos,char str)
{
assert(pos < _size);
if (_capacity == _size)
{
//reserve(2 * _capacity);//如果_capacity是0,就错了
reserve(_capacity == 0 ? 4 : 2 * _capacity);
}
//用变量
//int end = _size;
//while (end >=(int) pos) //int 类型的变量和size_t类型的进行比较都会转成size_t
//{
// _str[end+1] = _str[end];
// end--;
//}
//用指针也行
char* end = _str + _size;
while (end >= _str + pos)
{
*(end + 1) = *(end);
end--;
}
_str[pos] = str;
_size++;
return *this;
}
string& insert(size_t pos, const char *str)
{
assert(pos < _size);
int len = strlen(str);
if (len +_size> _capacity)
{
reserve(len+_size);
}
char* end = _str + _size;
while (end >= _str + pos)
{
*(end + len) = *(end);
end--;
}
strncpy(_str + pos, str, len);
_size=len+_size;
return *this;
}
//删
string& erase(int pos, size_t amount = npos)
{
assert(pos >= 0);
assert(pos <= _size);
if (amount > _size)
{
_str[pos] = '\0';
_size = pos;
}
else
{
for (int i = pos+amount; i <= _size; i++)
{
_str[i-amount] = _str[i];
}
}
return *this;
}
//查
int find(char str, int pos=0)
{
for (int i = pos; i < _size; i++)
{
if (_str[i] == str)
{
return i;
}
}
return -1;
}
int find(const char* str, int pos=0) //直接传一个字符串是const类型的,要用const接收
{
const char* spot = strstr(_str + pos, str);
if (spot)
{
return spot - _str;
}
else
{
return npos;
}
}
bool operator<(const string& s)
{
if (strcmp(_str, s._str) >= 0)
{
return false;
}
return true;
}
bool operator>(const string& s)
{
if (strcmp(_str, s._str) <= 0)
{
return false;
}
return true;
}
bool operator<=(const string& s)
{
return !operator>(s);
}
bool operator>=(const string& s)
{
return !operator<(s);
}
bool operator==(const string& s)
{
if (strcmp(_str, s._str) == 0)
{
return true;
}
return false;
}
bool operator!=(const string& s)
{
return !operator==(s);
}
//获取大小
int size()const
{
return _size;
}
int capacity()
{
return _capacity;
}
//打印
char* C_str()
{
return _str;
}
//[]重载
const char& operator[](int v)const //const类型的调这个
{
return _str[v];
}
char& operator[](int v)//这里就不能加const了,加了和上面就是相同的函数,不是重载函数
{
return _str[v];
}
void clear()
{
_size = 0;
_str[_size] = '\0';
}
private:
char* _str;
int _size;
int _capacity;
static const size_t npos;
}; 引用做参数和返回值能做到:如果做参数能在函数内部修改,如果做返回值,返回后还能修改.都能提高效率,减少拷贝
- 并不是所有地方都能用引用返回:注意:只有当除了函数作用域后还存在的对象才能用引用返回,如果出了作用域对象被销毁了就只能用传值返回.
- 传值返回回进行一次拷贝,1.4或者8自己考进寄存器,2.如果对象大,拷贝是考进上一个函数的栈帧
- size_t类型和int类型的差异,size_t是无符号整型,int是有符号的.两个类似类型相比,int又被转成无符号的,size_t -1就是32亿多,注意循环的条件那,
- getline(cin,s1);能把空格也放在s1里...重载流插入运算符重载,如果用in>>ch;当接收到空格或者换行时in就忽略调了,就一直死循环下去了.
- const修饰在成员函数后面实际是修饰*this,本质是保护成员变量在这个函数体内不被改变,返回值无所谓
- 函数前面和后面都加const,函数体内不能被改,返回值也不能被改,同时返回值也要拿const接收
- 可读可写的要实现两个版本,一个全加const,另一个 一个const也不加
- 是否设置有缘函数
- string的大小(64位操作系统linux下8字节(只用一个指针)开辟一片空间前八个字节存容量和大小,自己实现的12字节,vs下28字节)
- 扩容,往大扩,一次大概扩15个,编译器决定...往小扩,容量一直不变,直到容量缩小成15个,容量才会变回15..空间是好不容易申请的所以不释放,直到字符串能在string里数组(16个字节,有效15个)中存下,才释放空间.
- string的拷贝;有内存开辟的情况用深拷贝.......浅拷贝时:引用计数浅拷贝+写实拷贝(了解,设计复杂,特殊情况下有缺陷),多个对象拷贝一个对象的数据后,指向同一个空间,引用计数一直加,析构的时候引用计数先减,等到减到0再释放空间.写实拷贝是,没有对象写的时候共用空间,有对象写的时候,自己拷贝一份数据,自己去写属于自己的数据.注意修改引用计数.
- B();//匿名对象,生命周期是这一行.匿名对象当参数传给函数,不会构造两个和也不会拷贝构造,只拷贝构造一个真正的形参编译器的优化//f(B(2)):做参数只构造一个形参,//B bb = 3;构造B temp(3)加一个拷贝构造给bb,3构造一个匿名对象//B b=f()返回的时候只拷贝构造一次,f的返回值直接拷贝构造b.编译器优化//表达式连续的步骤中才有可能优化,优化的是减少构造临时的对象//string s2 = "hello";//隐式类型的转换,构造一个匿名对象拷贝给s2
|