-
引用做参数和返回值能做到:如果做参数能在函数内部修改,如果做返回值,返回后还能修改.都能提高效率,减少拷贝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
c++--->string的细节加模拟实现string
最新推荐文章于 2024-11-04 19:24:37 发布