为实现祖国统一而奋斗!为实现社会主义现代化而奋斗!为实现中华民族复兴而奋斗!
——By 一名社会主义建设积极分子
目录
一、实现概括:
1.先实现一个简单的string,只考虑资源管理深浅拷贝问题(暂不考虑增删查改)
对于浅拷贝的两个问题:
2. string完善的增、删、查、改、使用的string
完整源码及注释:
后记:●由于作者水平有限,文章难免存在谬误之处,敬请读者斧正,俚语成篇,恳望指教! ——By 作者:新晓·故知
一、实现概括:
模拟实现string类,最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数。根据string的底层原理,实现模拟string使其与库里的string(即std::string)具有相似的功能。由于库里的string类的功能较多,这里只模拟实现了较为常用的功能,
例如:iterator(模拟的string迭代器)、push_back、insert、reserve、resize、find、erase、c_str、ostream重载、istream重载、赋值运算符重载、[ ]重载、append以及比较运算符的重载等,甚至深拷贝构造函数的现代写法(资本写法)、赋值运算符重载的现代写法(资本写法)等。std::string中的功能较多,学习使用可登录cplusplus官网,参见string文档。
1.先实现一个简单的string,只考虑资源管理深浅拷贝问题(暂不考虑增删查改)
(1)string.h
(2)test.cpp:
深拷贝:
深拷贝:使得值相同,空间大小相同,但空间地址不同
对于浅拷贝的两个问题:
1.多次析构同一空间:引用计数,即最后一个拷贝构造的对象是否资源
2.一个对象修改会影响其他对象:做深拷贝,写时拷贝
2. string完善的增、删、查、改、使用的string
string.h:
test.cpp:
完整源码及注释:
(1)string.h:
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
using namespace std;
//模拟实现string
//1.先实现一个简单的string,只考虑资源管理深浅拷贝问题
//自定义命名空间,防止与库中的冲突
//namespace my
//{
// //先实现一个简单的string,只考虑资源管理深浅拷贝问题
// //暂不考虑增删查改
// class string
// {
// public:
// //构造函数
// string(const char* str)
// :_str(new char[strlen(str) + 1])
// {
// //不能直接 _str=str; 因为会权限放大
// strcpy(_str, str); //也拷贝了
// }
// //深拷贝函数 s2(s1)
// string(const string& s)
// :_str(new char[strlen(s._str) + 1])
// {
// strcpy(_str, s._str);
// }
// ~string()
// {
// if (_str)
// {
// delete[] _str;
// }
// }
// //s1=s3 ——>s1.operator=(&s1,s3)
// //赋值重载函数
// string& operator = (const string& s)
// {
// if (this != &s) //解决s1=s1,自己释放自己的空间
// {
// //先删除,再开辟赋值
// //如果new开辟失败,那s1作为原始数据被删除
//
// //先保存,再开辟赋值
// char* tmp = new char[strlen(s._str) + 1];
// strcpy(tmp, s._str);
// delete[] _str;
// _str = tmp;
// }
// return *this;
// }
// //c_str是string中的一个函数,具体详见string文档
// //获取等效的字符串
// const char* c_str() const
// {
// return _str;
// }
// //重载[]
// char& operator[](size_t pos)
// {
// assert(pos < strlen(_str));
// return _str[pos];
// }
// //计算字符串大小
// size_t size()
// {
// return strlen(_str);
// }
//
// private:
// char* _str;
//
// };
//}
//
2.string完善的增删查改和使用的string
//namespace my
//{
// class string
// {
// public:
// 构造函数
// //string(const char* str)
// // :_size(strlen(str))
// // ,_capacity(_size)
// //{
// // //要注意初始化顺序,取决于类的声明顺序
// // _str = new char[_capacity + 1];
// // //不能直接 _str=str; 因为会权限放大
// // strcpy(_str, str); //也拷贝了
// //}
// 默认构造函数(无参使用的)
// //string()
// // :_size(0)
// // ,_capacity(0)
// //{
// // _str = new char[1]; //将_str初始化为空字符串,string库就是这种做法
// // _str[0] = '0';
// //}
//
// //默认构造函数(全缺省版)
// string(const char* str="") // ""、" "均可以,' '是字符
// :_size(strlen(str))
// , _capacity(_size)
// {
// //要注意初始化顺序,取决于类的声明顺序
// _str = new char[_capacity + 1];
// //不能直接 _str=str; 因为会权限放大
// strcpy(_str, str); //也拷贝了
// }
// 深拷贝函数版本1 s2(s1)
// //string(const string& s)
// // :_str(new char[strlen(s._str) + 1])
// //{
// // strcpy(_str, s._str);
// //}
// //深拷贝函数版本2 s2(s1)
// string(const string& s)
// :_size(strlen(s._str))
// ,_capacity(_size)
// {
// _str=new char[_capacity + 1];
// strcpy(_str, s._str);
// }
//
// //析构函数
// ~string()
// {
// if (_str)
// {
// delete[] _str;
// }
// }
// //s1=s3 ——>s1.operator=(&s1,s3)
// //赋值重载函数
// string& operator = (const string& s)
// {
// if (this != &s) //解决s1=s1,自己释放自己的空间
// {
// //先保存,再开辟赋值
// char* tmp = new char[s._capacity + 1];
// strcpy(tmp, s._str);
// delete[] _str;
// _str = tmp;
// _size = s._size;
// _capacity = s._capacity;
// }
// return *this;
// }
// //c_str是string中的一个函数,具体详见string文档
// //获取等效的字符串
// const char* c_str() const
// {
// return _str;
// }
// //重载[]
// char& operator[](size_t pos)
// {
// assert(pos < _size);
// return _str[pos];
// }
// //重载[] const 提供两个版本的重载[] ,普通对象和const对象都可以调用
// const char& operator[](size_t pos) const
// {
// assert(pos < _size);
// return _str[pos];
// }
// //计算字符串大小
// //size_t size(const string* this)
// size_t size() const
// {
// return _size;
// }
//
// size_t capacity() const
// {
// return _capacity;
// }
// 尾插数据
// //void push_back(char ch)
// //{
// // if (_size == _capacity) //其实为_capacity开辟的多一个为 存储的空间,但那个不参与比较
// // {
// // char* tmp = new char[_capacity * 2 + 1];
// // strcpy(tmp, _str);
// // delete[] _str;
// // _str = tmp;
// // _capacity *= 2;
// // }
// // _str[_size] = ch;
// // ++_size;
// // _str[_size] = ' ';
// //}
//
// //尾插也可以使用+=(附用push_back)
// string& operator+=(char ch)
// {
// push_back(ch);
// return *this;
// }
// //预留扩容
// void reserve(size_t n)
// {
// if (n > _capacity)
// {
// char* tmp = new char[n + 1];
// strcpy(tmp, _str);
// delete[] _str;
// _str = tmp;
// _capacity = n;
// }
// }
// //尾插数据——附用reserve
// void push_back(char ch)
// {
// //if (_size == _capacity) //其实为_capacity开辟的多一个为 存储的空间,但那个不参与比较
// //{
// // //reserve( _capacity * 2);若_capacity为0,则出现bug
// // reserve(_capacity==0 ? 4 : _capacity * 2);
// //}
// //_str[_size] = ch;
// //++_size;
// //_str[_size] = ' ';
//
// //附用insert
// insert(_size, ch);
// }
// //追加到字符
// void append(const char*str)
// {
//
// //附用insert
// insert(_size, str);
// }
// //尾插也可以使用+=(附用append)
// string& operator+=(const char* str)
// {
// append(str);
// return *this;
// }
// //扩空间+初始化
// //删除部分数据,保留前n个
// void resize(size_t n, char ch = ' ')
// {
// //考虑到内存对齐,可能开辟的空间与n有些许微小出入
// if (n < _size)
// {
// _size = n;
// _str[_size] = ' ';
// }
// else
// {
// if (n > _capacity)
// {
// reserve(n);
// }
// for (size_t i = _size; i < n; ++i)
// {
// _str[i] = ch;
// }
// _size = n;
// _str[_size] = ' ';
// }
// }
//
// //迭代器
// typedef char* iterator;
// typedef const char* const_iterator;
//
// iterator begin()
// {
// return _str;
// }
// iterator end()
// {
// return _str + _size;
// }
// const_iterator begin() const
// {
// return _str;
// }
// const_iterator end() const
// {
// return _str + _size;
// }
// //头插数据
// //持续头插,不如尾插逆置
// //插入字符
// string& insert(size_t pos, char ch)
// {
// assert(pos <= _size); //pos = _size相当于尾插
// if (_size == _capacity)
// {
// reserve(_capacity == 0 ? 4 : _capacity * 2);
// }
// //size_t end = _size;
// //while (end >= pos) //--end会造成负数,而--end是size_t类型
// //{
// // _str[end + 1] = _str[end];
// // --end;
// //}
// 解决1:强转类型
// //int end = _size;
// //while (end >=(int) pos) //--end会造成负数,而--end是size_t类型
// //{
// // _str[end + 1] = _str[end];
// // --end;
// //}
// //解决2:修改end位置
// size_t end = _size+1;
// while (end > pos) //end等于0就停止
// {
// _str[end ] = _str[end-1];
// --end;
// }
// _str[pos] = ch;
// _size ++;
// return *this;
// }
// //插入字符串
// string& insert(size_t pos,const char* str)
// {
// assert(pos <= _size);
// size_t len=strlen(str);
// if (_size + len > _capacity)
// {
// reserve(_size + len);
// }
// size_t end = _size + len;
// while (end > pos + len - 1) //或者while (end >= pos + len) ,但pos、len均为0就有问题
// {
// _str[end] = _str[end - len];
// --end;
// }
// strncpy(_str + pos, str, len); //不能使用strcpy
// _size += len;
// return *this;
// }
// //删除
// string& erase(size_t pos, size_t len=npos)
// {
// assert(pos < _size);
// if (len == npos || pos + len >= _size)
// {
// _str[pos] = ' ';
// _size = pos;
// }
// else
// {
// size_t begin = pos + len;
// while (begin <= _size)
// {
// _str[begin - len] = _str[begin];
// ++begin;
// }
// _size -= len;
// }
// return *this;
// }
// //查找字符
// //The position of the first character of the first match.
// //If no matches were found, the function returns string::npos.
// size_t find(char ch,size_t pos=0)
// {
// for (; pos < _size; ++pos)
// {
// if (_str[pos] == ch)
// {
// return pos;
// }
// }
// return npos;
// }
// //查找字符串
// size_t find(const char*str, size_t pos = 0)
// {
// const char* p = strstr(_str + pos, str); //strstr暴力算法
// if (p == nullptr)
// {
// return npos;
// }
// else
// {
// return p - _str;
// }
// }
// void clear()
// {
// _str[0] = ' ';
// _size = 0;
// }
// private:
// char* _str;
// size_t _size; //有效字符个数,不包含
// size_t _capacity; //实际存储的有效字符的空间
// const static size_t npos;
//
// };
// //定义
// const size_t string::npos = -1;
// //这里不是成员函数,不在类里
// //运算符<重载
// bool operator<(const string& s1, const string& s2)
// {
// return strcmp(s1.c_str(), s2.c_str()) < 0;
// }
// //运算符==重载
// bool operator==(const string& s1, const string& s2)
// {
// return strcmp(s1.c_str(), s2.c_str()) == 0;
// }
// //运算符<=重载
// bool operator<=(const string& s1, const string& s2)
// {
// return s1 < s2 || s1 == s2;
// }
// //运算符>重载 (附用<=实现)
// bool operator>(const string& s1, const string& s2)
// {
// return !(s1 <= s2);
// }
// //运算符>=重载 (附用<实现)
// bool operator>=(const string& s1, const string& s2)
// {
// return !(s1 < s2);
// }
// //运算符!=重载 (附用==实现)
// bool operator!=(const string& s1, const string& s2)
// {
// return !(s1 == s2);
// }
// //流运算符重载
// ostream& operator<<(ostream& out, const string& s)
// {
// //out << s.c_str(); //无法打印不可见字符
// for (auto ch : s)
// {
// out << ch;
// }
// return out;
// }
// istream& operator>>(istream& in, string& s)
// {
// //s.clear();
// //char ch;
// in >> ch;
// //ch = in.get();
// //while (ch != ' ' && ch != 'n')
// //{
// // s += ch;
// // //in >> ch;
// // ch = in.get();
// //}
// //return in;
// //优化
// s.clear();
// char ch;
// ch = in.get();
// char buff[128] = { ' ' };
// size_t i = 0;
// while (ch != ' ' && ch != 'n')
// {
// buff[i++] = ch;
// if (i == 127)
// {
// s += buff;
// memset(buff, ' ', 128);
// i = 0;
// }
// ch = in.get();
// }
// s += buff;
// return in;
// }
// //getline
//
//}
//3.string完善的增删查改和使用的string(现代写法)
namespace my
{
class string
{
public:
构造函数
//string(const char* str)
// :_size(strlen(str))
// ,_capacity(_size)
//{
// //要注意初始化顺序,取决于类的声明顺序
// _str = new char[_capacity + 1];
// //不能直接 _str=str; 因为会权限放大
// strcpy(_str, str); //也拷贝了
//}
默认构造函数(无参使用的)
//string()
// :_size(0)
// ,_capacity(0)
//{
// _str = new char[1]; //将_str初始化为空字符串,string库就是这种做法
// _str[0] = '0';
//}
//默认构造函数(全缺省版)
string(const char* str = "") // ""、" "均可以,' '是字符
:_size(strlen(str))
, _capacity(_size)
{
//要注意初始化顺序,取决于类的声明顺序
_str = new char[_capacity + 1];
//不能直接 _str=str; 因为会权限放大
strcpy(_str, str); //也拷贝了
}
深拷贝函数版本1 s2(s1)
//string(const string& s)
// :_str(new char[strlen(s._str) + 1])
//{
// strcpy(_str, s._str);
//}
深拷贝函数版本2 s2(s1) //传统写法:本分实现,自劳
//string(const string& s)
// :_size(strlen(s._str))
// , _capacity(_size)
//{
// _str = new char[_capacity + 1];
// strcpy(_str, s._str);
//}
//深拷贝函数版本3 s2(s1) //现代写法:剥削行为,借他人之手,行私利,但简单
//tmp去调用构造函数:s1->s2:构造函数->拷贝构造函数->构造函数->swap
//tmp->s2
void swap(string& s)
{
//库里的swap,可交换任意类型
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
string(const string& s)
:_str(nullptr)
, _size(0)
, _capacity(0)
{
string tmp(s._str); //tmp是局部对象,出作用域会调用析构函数
swap(tmp);
}
//析构函数
~string()
{
if (_str)
{
delete[] _str;
}
}
//s1=s3 ——>s1.operator=(&s1,s3)
赋值重载函数--版本1 传统写法
//string& operator = (const string& s)
//{
// if (this != &s) //解决s1=s1,自己释放自己的空间
// {
// //先保存,再开辟赋值
// char* tmp = new char[s._capacity + 1];
// strcpy(tmp, s._str);
// delete[] _str;
// _str = tmp;
// _size = s._size;
// _capacity = s._capacity;
// }
// return *this;
//}
赋值重载函数--版本2 现代写法
//string& operator = (const string& s)
//{
// if (this != &s) //解决s1=s1,自己释放自己的空间
// {
// string tmp(s._str);
// swap(tmp);
// }
// return *this;
//}
赋值重载函数--版本3 现代写法
string& operator = (string s) //传值传参,引用返回
{
swap(s);
return *this;
}
//c_str是string中的一个函数,具体详见string文档
//获取等效的字符串
const char* c_str() const
{
return _str;
}
//重载[]
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
//重载[] const 提供两个版本的重载[] ,普通对象和const对象都可以调用
const char& operator[](size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
//计算字符串大小
//size_t size(const string* this)
size_t size() const
{
return _size;
}
size_t capacity() const
{
return _capacity;
}
尾插数据
//void push_back(char ch)
//{
// if (_size == _capacity) //其实为_capacity开辟的多一个为 存储的空间,但那个不参与比较
// {
// char* tmp = new char[_capacity * 2 + 1];
// strcpy(tmp, _str);
// delete[] _str;
// _str = tmp;
// _capacity *= 2;
// }
// _str[_size] = ch;
// ++_size;
// _str[_size] = ' ';
//}
//尾插也可以使用+=(附用push_back)
string& operator+=(char ch)
{
push_back(ch);
return *this;
}
//预留扩容
void reserve(size_t n)
{
if (n > _capacity)
{
char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
//尾插数据——附用reserve
void push_back(char ch)
{
//if (_size == _capacity) //其实为_capacity开辟的多一个为 存储的空间,但那个不参与比较
//{
// //reserve( _capacity * 2);若_capacity为0,则出现bug
// reserve(_capacity==0 ? 4 : _capacity * 2);
//}
//_str[_size] = ch;
//++_size;
//_str[_size] = ' ';
//附用insert
insert(_size, ch);
}
//追加到字符
void append(const char* str)
{
//附用insert
insert(_size, str);
}
//尾插也可以使用+=(附用append)
string& operator+=(const char* str)
{
append(str);
return *this;
}
//扩空间+初始化
//删除部分数据,保留前n个
void resize(size_t n, char ch = ' ')
{
//考虑到内存对齐,可能开辟的空间与n有些许微小出入
if (n < _size)
{
_size = n;
_str[_size] = ' ';
}
else
{
if (n > _capacity)
{
reserve(n);
}
for (size_t i = _size; i < n; ++i)
{
_str[i] = ch;
}
_size = n;
_str[_size] = ' ';
}
}
//迭代器
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
const_iterator begin() const
{
return _str;
}
const_iterator end() const
{
return _str + _size;
}
//头插数据
//持续头插,不如尾插逆置
//插入字符
string& insert(size_t pos, char ch)
{
assert(pos <= _size); //pos = _size相当于尾插
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : _capacity * 2);
}
//size_t end = _size;
//while (end >= pos) //--end会造成负数,而--end是size_t类型
//{
// _str[end + 1] = _str[end];
// --end;
//}
解决1:强转类型
//int end = _size;
//while (end >=(int) pos) //--end会造成负数,而--end是size_t类型
//{
// _str[end + 1] = _str[end];
// --end;
//}
//解决2:修改end位置
size_t end = _size + 1;
while (end > pos) //end等于0就停止
{
_str[end] = _str[end - 1];
--end;
}
_str[pos] = ch;
_size++;
return *this;
}
//插入字符串
string& insert(size_t pos, const char* str)
{
assert(pos <= _size);
size_t len = strlen(str);
if (_size + len > _capacity)
{
reserve(_size + len);
}
size_t end = _size + len;
while (end > pos + len - 1) //或者while (end >= pos + len) ,但pos、len均为0就有问题
{
_str[end] = _str[end - len];
--end;
}
strncpy(_str + pos, str, len); //不能使用strcpy
_size += len;
return *this;
}
//删除
string& erase(size_t pos, size_t len = npos)
{
assert(pos < _size);
if (len == npos || pos + len >= _size)
{
_str[pos] = ' ';
_size = pos;
}
else
{
size_t begin = pos + len;
while (begin <= _size)
{
_str[begin - len] = _str[begin];
++begin;
}
_size -= len;
}
return *this;
}
//查找字符
//The position of the first character of the first match.
//If no matches were found, the function returns string::npos.
size_t find(char ch, size_t pos = 0)
{
for (; pos < _size; ++pos)
{
if (_str[pos] == ch)
{
return pos;
}
}
return npos;
}
//查找字符串
size_t find(const char* str, size_t pos = 0)
{
const char* p = strstr(_str + pos, str); //strstr暴力算法
if (p == nullptr)
{
return npos;
}
else
{
return p - _str;
}
}
void clear()
{
_str[0] = ' ';
_size = 0;
}
private:
char* _str;
size_t _size; //有效字符个数,不包含
size_t _capacity; //实际存储的有效字符的空间
const static size_t npos;
};
//定义
const size_t string::npos = -1;
//这里不是成员函数,不在类里
//运算符<重载
bool operator<(const string& s1, const string& s2)
{
return strcmp(s1.c_str(), s2.c_str()) < 0;
}
//运算符==重载
bool operator==(const string& s1, const string& s2)
{
return strcmp(s1.c_str(), s2.c_str()) == 0;
}
//运算符<=重载
bool operator<=(const string& s1, const string& s2)
{
return s1 < s2 || s1 == s2;
}
//运算符>重载 (附用<=实现)
bool operator>(const string& s1, const string& s2)
{
return !(s1 <= s2);
}
//运算符>=重载 (附用<实现)
bool operator>=(const string& s1, const string& s2)
{
return !(s1 < s2);
}
//运算符!=重载 (附用==实现)
bool operator!=(const string& s1, const string& s2)
{
return !(s1 == s2);
}
//流运算符重载
ostream& operator<<(ostream& out, const string& s)
{
//out << s.c_str(); //无法打印不可见字符
for (auto ch : s)
{
out << ch;
}
return out;
}
istream& operator>>(istream& in, string& s)
{
//s.clear();
//char ch;
in >> ch;
//ch = in.get();
//while (ch != ' ' && ch != 'n')
//{
// s += ch;
// //in >> ch;
// ch = in.get();
//}
//return in;
//优化
s.clear();
char ch;
ch = in.get();
char buff[128] = { ' ' };
size_t i = 0;
while (ch != ' ' && ch != 'n')
{
buff[i++] = ch;
if (i == 127)
{
s += buff;
memset(buff, ' ', 128);
i = 0;
}
ch = in.get();
}
s += buff;
return in;
}
//getline
}
//类型转换函数
//atoi C
//itoa C
//stoi C++11
//to_string
(2)test.cpp:
#include "string.h"
//1.基本初始化测试
void TestString1()
{
my::string s1("hello,world");
cout << s1.c_str() << endl;
//修改测试
s1[0] = 'x'; //s1.operator[](0)='x';
cout << s1.c_str() << endl;
//读取测试
for (size_t i = 0; i < s1.size(); ++i)
{
cout << s1[i] << " ";
}
cout << endl;
}
//2.浅拷贝及其问题测试
void TestString2()
{
//浅拷贝带来的问题:
//1.析构两次,程序崩溃 2.修改一个值,另一个也被改变
my::string s1("hello,world");
my::string s2(s1); //调用拷贝构造函数
cout << s1.c_str() << endl;
cout << s2.c_str() << endl;
}
//3.深拷贝测试
void TestString3()
{
//深拷贝:使得值相同,空间大小相同,但空间地址不同
my::string s1("hello,world");
my::string s2(s1); //调用深拷贝构造函数
cout << s1.c_str() << endl;
cout << s2.c_str() << endl;
s1[0] = 'x';
cout << s1.c_str() << endl;
cout << s2.c_str() << endl;
}
//4.赋值重载测试
void TestString4()
{
//赋值面临的问题与浅拷贝相似
my::string s1("hello,world");
my::string s2(s1); //调用深拷贝构造函数
my::string s3("qqqqqqqqqq");
s1 = s3; //赋值
cout << s1.c_str() << endl;
cout << s2.c_str() << endl;
cout << s3.c_str() << endl;
}
//int main()
//{
// //TestString1();
// //TestString2();
// //TestString3();
// TestString4();
// //对于new的异常捕获
// try
// {
// TestString4();
// }
// catch (const exception& e)
// {
// cout << e.what() << endl;
// }
// return 0;
//}
//5.增删查改测试
void TestString5()
{
my::string s1("hello,world");
cout << s1.c_str() << endl;
my::string s2;
cout << s2.c_str() << endl;
}
//6.尾插测试+扩容测试
void TestString6()
{
//my::string s1("hello,world");
//cout << s1.c_str() << endl;
使用push_back
//s1.push_back('y');
//cout << s1.c_str() << endl;
//s1.push_back('y');
//cout << s1.c_str() << endl;
使用重载+= (附用push_back)
//s1 += '6';
//s1 += '7';
//s1 += '8';
//cout << s1.c_str() << endl;
使用重载+= (附用reserve)
//s1 += 'a';
//s1 += 'b';
//s1 += 'c';
//cout << s1.c_str() << endl;
//my::string s2; //reserve解决空串_capacity=0,再去_capacity*2仍为0
//s2.reserve(20); //直接开辟指定空间
//库里的string::resize
std::string s3("cplusplus");
s3.resize(20, 'x');
s3.resize(5, 'x');
cout << s3 << endl;
//模拟实现的string::resize
my::string s4("stringtest");
s4.resize(5, 'y');
s4.resize(15, 'g');
cout << s4.c_str() << endl;
}
//7.遍历测试
void TestString7()
{
my::string s1("hello,world");
//方式1:下标+[]
for (size_t i = 0; i < s1.size(); ++i)
{
s1[i] += 1;
cout << s1[i] << " ";
}
cout << endl;
//方式2:迭代器
my::string::iterator it = s1.begin();
while (it != s1.end())
{
*it -= 1;
cout << *it << " ";
++it;
}
cout << endl;
//方式3:范围for——底层被替换成迭代器访问
for (auto& ch : s1)
{
cout << ch << " ";
ch += 1;
}
cout << endl;
for (auto ch : s1)
{
cout << ch << " ";
}
cout << endl;
}
//const对象权限测试
void func(const my::string& s) //string的拷贝是深拷贝,使用引用减少拷贝
{
//方式1:下标+[]
for (size_t i = 0; i < s.size(); ++i)
{
//s[i] += 1; //这里传给const形参,不能写
cout << s[i] << " ";
}
cout << endl;
//方式2:迭代器
my::string::const_iterator it = s.begin();
while (it != s.end())
{
/
my::string s4("hello,world");
cin >> s4;
cout << s4 << endl;
}
//12.赋值重载测试
void TestString12()
{
my::string s1("hello,world");
my::string s2(s1);
cout << s2<< endl;
my::string s3;
s3 = s1;
cout << s3 << endl;
}
//13.转换函数测试
void TestString13()
{
int i;
cin >> i;
string s1 = to_string(i); //to_string是库里的
cout << s1 << endl;
int val = stoi(s1); //stoi是库里的
cout << s1 << endl;
}
int main()
{
//TestString1();
//TestString2();
//TestString3();
//TestString4();
//TestString5();
//TestString6();
//TestString7();
//func("hello,world");
//TestString8();
//TestString9();
//TestString10();
//TestString11();
//TestString12();
TestString13();
//对于new的异常捕获
return 0;
}
后记:
●由于作者水平有限,文章难免存在谬误之处,敬请读者斧正,俚语成篇,恳望指教!
——By 作者:新晓·故知
模拟实现string类,最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数。根据string的底层原理,实现模拟string使其与库里的string(即std::string)具有相似的功能。由于库里的string类的功能较多,这里只模拟实现了较为常用的功能,
例如:iterator(模拟的string迭代器)、push_back、insert、reserve、resize、find、erase、c_str、ostream重载、istream重载、赋值运算符重载、[ ]重载、append以及比较运算符的重载等,甚至深拷贝构造函数的现代写法(资本写法)、赋值运算符重载的现代写法(资本写法)等。std::string中的功能较多,学习使用可登录cplusplus官网,参见string文档。
(1)string.h
(2)test.cpp:
深拷贝:
深拷贝:使得值相同,空间大小相同,但空间地址不同
对于浅拷贝的两个问题:
1.多次析构同一空间:引用计数,即最后一个拷贝构造的对象是否资源
2.一个对象修改会影响其他对象:做深拷贝,写时拷贝
2. string完善的增、删、查、改、使用的string
string.h:
test.cpp:
完整源码及注释:
(1)string.h:
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
using namespace std;
//模拟实现string
//1.先实现一个简单的string,只考虑资源管理深浅拷贝问题
//自定义命名空间,防止与库中的冲突
//namespace my
//{
// //先实现一个简单的string,只考虑资源管理深浅拷贝问题
// //暂不考虑增删查改
// class string
// {
// public:
// //构造函数
// string(const char* str)
// :_str(new char[strlen(str) + 1])
// {
// //不能直接 _str=str; 因为会权限放大
// strcpy(_str, str); //也拷贝了
// }
// //深拷贝函数 s2(s1)
// string(const string& s)
// :_str(new char[strlen(s._str) + 1])
// {
// strcpy(_str, s._str);
// }
// ~string()
// {
// if (_str)
// {
// delete[] _str;
// }
// }
// //s1=s3 ——>s1.operator=(&s1,s3)
// //赋值重载函数
// string& operator = (const string& s)
// {
// if (this != &s) //解决s1=s1,自己释放自己的空间
// {
// //先删除,再开辟赋值
// //如果new开辟失败,那s1作为原始数据被删除
//
// //先保存,再开辟赋值
// char* tmp = new char[strlen(s._str) + 1];
// strcpy(tmp, s._str);
// delete[] _str;
// _str = tmp;
// }
// return *this;
// }
// //c_str是string中的一个函数,具体详见string文档
// //获取等效的字符串
// const char* c_str() const
// {
// return _str;
// }
// //重载[]
// char& operator[](size_t pos)
// {
// assert(pos < strlen(_str));
// return _str[pos];
// }
// //计算字符串大小
// size_t size()
// {
// return strlen(_str);
// }
//
// private:
// char* _str;
//
// };
//}
//
2.string完善的增删查改和使用的string
//namespace my
//{
// class string
// {
// public:
// 构造函数
// //string(const char* str)
// // :_size(strlen(str))
// // ,_capacity(_size)
// //{
// // //要注意初始化顺序,取决于类的声明顺序
// // _str = new char[_capacity + 1];
// // //不能直接 _str=str; 因为会权限放大
// // strcpy(_str, str); //也拷贝了
// //}
// 默认构造函数(无参使用的)
// //string()
// // :_size(0)
// // ,_capacity(0)
// //{
// // _str = new char[1]; //将_str初始化为空字符串,string库就是这种做法
// // _str[0] = '0';
// //}
//
// //默认构造函数(全缺省版)
// string(const char* str="") // ""、" "均可以,' '是字符
// :_size(strlen(str))
// , _capacity(_size)
// {
// //要注意初始化顺序,取决于类的声明顺序
// _str = new char[_capacity + 1];
// //不能直接 _str=str; 因为会权限放大
// strcpy(_str, str); //也拷贝了
// }
// 深拷贝函数版本1 s2(s1)
// //string(const string& s)
// // :_str(new char[strlen(s._str) + 1])
// //{
// // strcpy(_str, s._str);
// //}
// //深拷贝函数版本2 s2(s1)
// string(const string& s)
// :_size(strlen(s._str))
// ,_capacity(_size)
// {
// _str=new char[_capacity + 1];
// strcpy(_str, s._str);
// }
//
// //析构函数
// ~string()
// {
// if (_str)
// {
// delete[] _str;
// }
// }
// //s1=s3 ——>s1.operator=(&s1,s3)
// //赋值重载函数
// string& operator = (const string& s)
// {
// if (this != &s) //解决s1=s1,自己释放自己的空间
// {
// //先保存,再开辟赋值
// char* tmp = new char[s._capacity + 1];
// strcpy(tmp, s._str);
// delete[] _str;
// _str = tmp;
// _size = s._size;
// _capacity = s._capacity;
// }
// return *this;
// }
// //c_str是string中的一个函数,具体详见string文档
// //获取等效的字符串
// const char* c_str() const
// {
// return _str;
// }
// //重载[]
// char& operator[](size_t pos)
// {
// assert(pos < _size);
// return _str[pos];
// }
// //重载[] const 提供两个版本的重载[] ,普通对象和const对象都可以调用
// const char& operator[](size_t pos) const
// {
// assert(pos < _size);
// return _str[pos];
// }
// //计算字符串大小
// //size_t size(const string* this)
// size_t size() const
// {
// return _size;
// }
//
// size_t capacity() const
// {
// return _capacity;
// }
// 尾插数据
// //void push_back(char ch)
// //{
// // if (_size == _capacity) //其实为_capacity开辟的多一个为 存储的空间,但那个不参与比较
// // {
// // char* tmp = new char[_capacity * 2 + 1];
// // strcpy(tmp, _str);
// // delete[] _str;
// // _str = tmp;
// // _capacity *= 2;
// // }
// // _str[_size] = ch;
// // ++_size;
// // _str[_size] = ' ';
// //}
//
// //尾插也可以使用+=(附用push_back)
// string& operator+=(char ch)
// {
// push_back(ch);
// return *this;
// }
// //预留扩容
// void reserve(size_t n)
// {
// if (n > _capacity)
// {
// char* tmp = new char[n + 1];
// strcpy(tmp, _str);
// delete[] _str;
// _str = tmp;
// _capacity = n;
// }
// }
// //尾插数据——附用reserve
// void push_back(char ch)
// {
// //if (_size == _capacity) //其实为_capacity开辟的多一个为 存储的空间,但那个不参与比较
// //{
// // //reserve( _capacity * 2);若_capacity为0,则出现bug
// // reserve(_capacity==0 ? 4 : _capacity * 2);
// //}
// //_str[_size] = ch;
// //++_size;
// //_str[_size] = ' ';
//
// //附用insert
// insert(_size, ch);
// }
// //追加到字符
// void append(const char*str)
// {
//
// //附用insert
// insert(_size, str);
// }
// //尾插也可以使用+=(附用append)
// string& operator+=(const char* str)
// {
// append(str);
// return *this;
// }
// //扩空间+初始化
// //删除部分数据,保留前n个
// void resize(size_t n, char ch = ' ')
// {
// //考虑到内存对齐,可能开辟的空间与n有些许微小出入
// if (n < _size)
// {
// _size = n;
// _str[_size] = ' ';
// }
// else
// {
// if (n > _capacity)
// {
// reserve(n);
// }
// for (size_t i = _size; i < n; ++i)
// {
// _str[i] = ch;
// }
// _size = n;
// _str[_size] = ' ';
// }
// }
//
// //迭代器
// typedef char* iterator;
// typedef const char* const_iterator;
//
// iterator begin()
// {
// return _str;
// }
// iterator end()
// {
// return _str + _size;
// }
// const_iterator begin() const
// {
// return _str;
// }
// const_iterator end() const
// {
// return _str + _size;
// }
// //头插数据
// //持续头插,不如尾插逆置
// //插入字符
// string& insert(size_t pos, char ch)
// {
// assert(pos <= _size); //pos = _size相当于尾插
// if (_size == _capacity)
// {
// reserve(_capacity == 0 ? 4 : _capacity * 2);
// }
// //size_t end = _size;
// //while (end >= pos) //--end会造成负数,而--end是size_t类型
// //{
// // _str[end + 1] = _str[end];
// // --end;
// //}
// 解决1:强转类型
// //int end = _size;
// //while (end >=(int) pos) //--end会造成负数,而--end是size_t类型
// //{
// // _str[end + 1] = _str[end];
// // --end;
// //}
// //解决2:修改end位置
// size_t end = _size+1;
// while (end > pos) //end等于0就停止
// {
// _str[end ] = _str[end-1];
// --end;
// }
// _str[pos] = ch;
// _size ++;
// return *this;
// }
// //插入字符串
// string& insert(size_t pos,const char* str)
// {
// assert(pos <= _size);
// size_t len=strlen(str);
// if (_size + len > _capacity)
// {
// reserve(_size + len);
// }
// size_t end = _size + len;
// while (end > pos + len - 1) //或者while (end >= pos + len) ,但pos、len均为0就有问题
// {
// _str[end] = _str[end - len];
// --end;
// }
// strncpy(_str + pos, str, len); //不能使用strcpy
// _size += len;
// return *this;
// }
// //删除
// string& erase(size_t pos, size_t len=npos)
// {
// assert(pos < _size);
// if (len == npos || pos + len >= _size)
// {
// _str[pos] = ' ';
// _size = pos;
// }
// else
// {
// size_t begin = pos + len;
// while (begin <= _size)
// {
// _str[begin - len] = _str[begin];
// ++begin;
// }
// _size -= len;
// }
// return *this;
// }
// //查找字符
// //The position of the first character of the first match.
// //If no matches were found, the function returns string::npos.
// size_t find(char ch,size_t pos=0)
// {
// for (; pos < _size; ++pos)
// {
// if (_str[pos] == ch)
// {
// return pos;
// }
// }
// return npos;
// }
// //查找字符串
// size_t find(const char*str, size_t pos = 0)
// {
// const char* p = strstr(_str + pos, str); //strstr暴力算法
// if (p == nullptr)
// {
// return npos;
// }
// else
// {
// return p - _str;
// }
// }
// void clear()
// {
// _str[0] = ' ';
// _size = 0;
// }
// private:
// char* _str;
// size_t _size; //有效字符个数,不包含
// size_t _capacity; //实际存储的有效字符的空间
// const static size_t npos;
//
// };
// //定义
// const size_t string::npos = -1;
// //这里不是成员函数,不在类里
// //运算符<重载
// bool operator<(const string& s1, const string& s2)
// {
// return strcmp(s1.c_str(), s2.c_str()) < 0;
// }
// //运算符==重载
// bool operator==(const string& s1, const string& s2)
// {
// return strcmp(s1.c_str(), s2.c_str()) == 0;
// }
// //运算符<=重载
// bool operator<=(const string& s1, const string& s2)
// {
// return s1 < s2 || s1 == s2;
// }
// //运算符>重载 (附用<=实现)
// bool operator>(const string& s1, const string& s2)
// {
// return !(s1 <= s2);
// }
// //运算符>=重载 (附用<实现)
// bool operator>=(const string& s1, const string& s2)
// {
// return !(s1 < s2);
// }
// //运算符!=重载 (附用==实现)
// bool operator!=(const string& s1, const string& s2)
// {
// return !(s1 == s2);
// }
// //流运算符重载
// ostream& operator<<(ostream& out, const string& s)
// {
// //out << s.c_str(); //无法打印不可见字符
// for (auto ch : s)
// {
// out << ch;
// }
// return out;
// }
// istream& operator>>(istream& in, string& s)
// {
// //s.clear();
// //char ch;
// in >> ch;
// //ch = in.get();
// //while (ch != ' ' && ch != 'n')
// //{
// // s += ch;
// // //in >> ch;
// // ch = in.get();
// //}
// //return in;
// //优化
// s.clear();
// char ch;
// ch = in.get();
// char buff[128] = { ' ' };
// size_t i = 0;
// while (ch != ' ' && ch != 'n')
// {
// buff[i++] = ch;
// if (i == 127)
// {
// s += buff;
// memset(buff, ' ', 128);
// i = 0;
// }
// ch = in.get();
// }
// s += buff;
// return in;
// }
// //getline
//
//}
//3.string完善的增删查改和使用的string(现代写法)
namespace my
{
class string
{
public:
构造函数
//string(const char* str)
// :_size(strlen(str))
// ,_capacity(_size)
//{
// //要注意初始化顺序,取决于类的声明顺序
// _str = new char[_capacity + 1];
// //不能直接 _str=str; 因为会权限放大
// strcpy(_str, str); //也拷贝了
//}
默认构造函数(无参使用的)
//string()
// :_size(0)
// ,_capacity(0)
//{
// _str = new char[1]; //将_str初始化为空字符串,string库就是这种做法
// _str[0] = '0';
//}
//默认构造函数(全缺省版)
string(const char* str = "") // ""、" "均可以,' '是字符
:_size(strlen(str))
, _capacity(_size)
{
//要注意初始化顺序,取决于类的声明顺序
_str = new char[_capacity + 1];
//不能直接 _str=str; 因为会权限放大
strcpy(_str, str); //也拷贝了
}
深拷贝函数版本1 s2(s1)
//string(const string& s)
// :_str(new char[strlen(s._str) + 1])
//{
// strcpy(_str, s._str);
//}
深拷贝函数版本2 s2(s1) //传统写法:本分实现,自劳
//string(const string& s)
// :_size(strlen(s._str))
// , _capacity(_size)
//{
// _str = new char[_capacity + 1];
// strcpy(_str, s._str);
//}
//深拷贝函数版本3 s2(s1) //现代写法:剥削行为,借他人之手,行私利,但简单
//tmp去调用构造函数:s1->s2:构造函数->拷贝构造函数->构造函数->swap
//tmp->s2
void swap(string& s)
{
//库里的swap,可交换任意类型
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
string(const string& s)
:_str(nullptr)
, _size(0)
, _capacity(0)
{
string tmp(s._str); //tmp是局部对象,出作用域会调用析构函数
swap(tmp);
}
//析构函数
~string()
{
if (_str)
{
delete[] _str;
}
}
//s1=s3 ——>s1.operator=(&s1,s3)
赋值重载函数--版本1 传统写法
//string& operator = (const string& s)
//{
// if (this != &s) //解决s1=s1,自己释放自己的空间
// {
// //先保存,再开辟赋值
// char* tmp = new char[s._capacity + 1];
// strcpy(tmp, s._str);
// delete[] _str;
// _str = tmp;
// _size = s._size;
// _capacity = s._capacity;
// }
// return *this;
//}
赋值重载函数--版本2 现代写法
//string& operator = (const string& s)
//{
// if (this != &s) //解决s1=s1,自己释放自己的空间
// {
// string tmp(s._str);
// swap(tmp);
// }
// return *this;
//}
赋值重载函数--版本3 现代写法
string& operator = (string s) //传值传参,引用返回
{
swap(s);
return *this;
}
//c_str是string中的一个函数,具体详见string文档
//获取等效的字符串
const char* c_str() const
{
return _str;
}
//重载[]
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
//重载[] const 提供两个版本的重载[] ,普通对象和const对象都可以调用
const char& operator[](size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
//计算字符串大小
//size_t size(const string* this)
size_t size() const
{
return _size;
}
size_t capacity() const
{
return _capacity;
}
尾插数据
//void push_back(char ch)
//{
// if (_size == _capacity) //其实为_capacity开辟的多一个为 存储的空间,但那个不参与比较
// {
// char* tmp = new char[_capacity * 2 + 1];
// strcpy(tmp, _str);
// delete[] _str;
// _str = tmp;
// _capacity *= 2;
// }
// _str[_size] = ch;
// ++_size;
// _str[_size] = ' ';
//}
//尾插也可以使用+=(附用push_back)
string& operator+=(char ch)
{
push_back(ch);
return *this;
}
//预留扩容
void reserve(size_t n)
{
if (n > _capacity)
{
char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
//尾插数据——附用reserve
void push_back(char ch)
{
//if (_size == _capacity) //其实为_capacity开辟的多一个为 存储的空间,但那个不参与比较
//{
// //reserve( _capacity * 2);若_capacity为0,则出现bug
// reserve(_capacity==0 ? 4 : _capacity * 2);
//}
//_str[_size] = ch;
//++_size;
//_str[_size] = ' ';
//附用insert
insert(_size, ch);
}
//追加到字符
void append(const char* str)
{
//附用insert
insert(_size, str);
}
//尾插也可以使用+=(附用append)
string& operator+=(const char* str)
{
append(str);
return *this;
}
//扩空间+初始化
//删除部分数据,保留前n个
void resize(size_t n, char ch = ' ')
{
//考虑到内存对齐,可能开辟的空间与n有些许微小出入
if (n < _size)
{
_size = n;
_str[_size] = ' ';
}
else
{
if (n > _capacity)
{
reserve(n);
}
for (size_t i = _size; i < n; ++i)
{
_str[i] = ch;
}
_size = n;
_str[_size] = ' ';
}
}
//迭代器
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
const_iterator begin() const
{
return _str;
}
const_iterator end() const
{
return _str + _size;
}
//头插数据
//持续头插,不如尾插逆置
//插入字符
string& insert(size_t pos, char ch)
{
assert(pos <= _size); //pos = _size相当于尾插
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : _capacity * 2);
}
//size_t end = _size;
//while (end >= pos) //--end会造成负数,而--end是size_t类型
//{
// _str[end + 1] = _str[end];
// --end;
//}
解决1:强转类型
//int end = _size;
//while (end >=(int) pos) //--end会造成负数,而--end是size_t类型
//{
// _str[end + 1] = _str[end];
// --end;
//}
//解决2:修改end位置
size_t end = _size + 1;
while (end > pos) //end等于0就停止
{
_str[end] = _str[end - 1];
--end;
}
_str[pos] = ch;
_size++;
return *this;
}
//插入字符串
string& insert(size_t pos, const char* str)
{
assert(pos <= _size);
size_t len = strlen(str);
if (_size + len > _capacity)
{
reserve(_size + len);
}
size_t end = _size + len;
while (end > pos + len - 1) //或者while (end >= pos + len) ,但pos、len均为0就有问题
{
_str[end] = _str[end - len];
--end;
}
strncpy(_str + pos, str, len); //不能使用strcpy
_size += len;
return *this;
}
//删除
string& erase(size_t pos, size_t len = npos)
{
assert(pos < _size);
if (len == npos || pos + len >= _size)
{
_str[pos] = ' ';
_size = pos;
}
else
{
size_t begin = pos + len;
while (begin <= _size)
{
_str[begin - len] = _str[begin];
++begin;
}
_size -= len;
}
return *this;
}
//查找字符
//The position of the first character of the first match.
//If no matches were found, the function returns string::npos.
size_t find(char ch, size_t pos = 0)
{
for (; pos < _size; ++pos)
{
if (_str[pos] == ch)
{
return pos;
}
}
return npos;
}
//查找字符串
size_t find(const char* str, size_t pos = 0)
{
const char* p = strstr(_str + pos, str); //strstr暴力算法
if (p == nullptr)
{
return npos;
}
else
{
return p - _str;
}
}
void clear()
{
_str[0] = ' ';
_size = 0;
}
private:
char* _str;
size_t _size; //有效字符个数,不包含
size_t _capacity; //实际存储的有效字符的空间
const static size_t npos;
};
//定义
const size_t string::npos = -1;
//这里不是成员函数,不在类里
//运算符<重载
bool operator<(const string& s1, const string& s2)
{
return strcmp(s1.c_str(), s2.c_str()) < 0;
}
//运算符==重载
bool operator==(const string& s1, const string& s2)
{
return strcmp(s1.c_str(), s2.c_str()) == 0;
}
//运算符<=重载
bool operator<=(const string& s1, const string& s2)
{
return s1 < s2 || s1 == s2;
}
//运算符>重载 (附用<=实现)
bool operator>(const string& s1, const string& s2)
{
return !(s1 <= s2);
}
//运算符>=重载 (附用<实现)
bool operator>=(const string& s1, const string& s2)
{
return !(s1 < s2);
}
//运算符!=重载 (附用==实现)
bool operator!=(const string& s1, const string& s2)
{
return !(s1 == s2);
}
//流运算符重载
ostream& operator<<(ostream& out, const string& s)
{
//out << s.c_str(); //无法打印不可见字符
for (auto ch : s)
{
out << ch;
}
return out;
}
istream& operator>>(istream& in, string& s)
{
//s.clear();
//char ch;
in >> ch;
//ch = in.get();
//while (ch != ' ' && ch != 'n')
//{
// s += ch;
// //in >> ch;
// ch = in.get();
//}
//return in;
//优化
s.clear();
char ch;
ch = in.get();
char buff[128] = { ' ' };
size_t i = 0;
while (ch != ' ' && ch != 'n')
{
buff[i++] = ch;
if (i == 127)
{
s += buff;
memset(buff, ' ', 128);
i = 0;
}
ch = in.get();
}
s += buff;
return in;
}
//getline
}
//类型转换函数
//atoi C
//itoa C
//stoi C++11
//to_string
(2)test.cpp:
#include "string.h"
//1.基本初始化测试
void TestString1()
{
my::string s1("hello,world");
cout << s1.c_str() << endl;
//修改测试
s1[0] = 'x'; //s1.operator[](0)='x';
cout << s1.c_str() << endl;
//读取测试
for (size_t i = 0; i < s1.size(); ++i)
{
cout << s1[i] << " ";
}
cout << endl;
}
//2.浅拷贝及其问题测试
void TestString2()
{
//浅拷贝带来的问题:
//1.析构两次,程序崩溃 2.修改一个值,另一个也被改变
my::string s1("hello,world");
my::string s2(s1); //调用拷贝构造函数
cout << s1.c_str() << endl;
cout << s2.c_str() << endl;
}
//3.深拷贝测试
void TestString3()
{
//深拷贝:使得值相同,空间大小相同,但空间地址不同
my::string s1("hello,world");
my::string s2(s1); //调用深拷贝构造函数
cout << s1.c_str() << endl;
cout << s2.c_str() << endl;
s1[0] = 'x';
cout << s1.c_str() << endl;
cout << s2.c_str() << endl;
}
//4.赋值重载测试
void TestString4()
{
//赋值面临的问题与浅拷贝相似
my::string s1("hello,world");
my::string s2(s1); //调用深拷贝构造函数
my::string s3("qqqqqqqqqq");
s1 = s3; //赋值
cout << s1.c_str() << endl;
cout << s2.c_str() << endl;
cout << s3.c_str() << endl;
}
//int main()
//{
// //TestString1();
// //TestString2();
// //TestString3();
// TestString4();
// //对于new的异常捕获
// try
// {
// TestString4();
// }
// catch (const exception& e)
// {
// cout << e.what() << endl;
// }
// return 0;
//}
//5.增删查改测试
void TestString5()
{
my::string s1("hello,world");
cout << s1.c_str() << endl;
my::string s2;
cout << s2.c_str() << endl;
}
//6.尾插测试+扩容测试
void TestString6()
{
//my::string s1("hello,world");
//cout << s1.c_str() << endl;
使用push_back
//s1.push_back('y');
//cout << s1.c_str() << endl;
//s1.push_back('y');
//cout << s1.c_str() << endl;
使用重载+= (附用push_back)
//s1 += '6';
//s1 += '7';
//s1 += '8';
//cout << s1.c_str() << endl;
使用重载+= (附用reserve)
//s1 += 'a';
//s1 += 'b';
//s1 += 'c';
//cout << s1.c_str() << endl;
//my::string s2; //reserve解决空串_capacity=0,再去_capacity*2仍为0
//s2.reserve(20); //直接开辟指定空间
//库里的string::resize
std::string s3("cplusplus");
s3.resize(20, 'x');
s3.resize(5, 'x');
cout << s3 << endl;
//模拟实现的string::resize
my::string s4("stringtest");
s4.resize(5, 'y');
s4.resize(15, 'g');
cout << s4.c_str() << endl;
}
//7.遍历测试
void TestString7()
{
my::string s1("hello,world");
//方式1:下标+[]
for (size_t i = 0; i < s1.size(); ++i)
{
s1[i] += 1;
cout << s1[i] << " ";
}
cout << endl;
//方式2:迭代器
my::string::iterator it = s1.begin();
while (it != s1.end())
{
*it -= 1;
cout << *it << " ";
++it;
}
cout << endl;
//方式3:范围for——底层被替换成迭代器访问
for (auto& ch : s1)
{
cout << ch << " ";
ch += 1;
}
cout << endl;
for (auto ch : s1)
{
cout << ch << " ";
}
cout << endl;
}
//const对象权限测试
void func(const my::string& s) //string的拷贝是深拷贝,使用引用减少拷贝
{
//方式1:下标+[]
for (size_t i = 0; i < s.size(); ++i)
{
//s[i] += 1; //这里传给const形参,不能写
cout << s[i] << " ";
}
cout << endl;
//方式2:迭代器
my::string::const_iterator it = s.begin();
while (it != s.end())
{
/
my::string s4("hello,world");
cin >> s4;
cout << s4 << endl;
}
//12.赋值重载测试
void TestString12()
{
my::string s1("hello,world");
my::string s2(s1);
cout << s2<< endl;
my::string s3;
s3 = s1;
cout << s3 << endl;
}
//13.转换函数测试
void TestString13()
{
int i;
cin >> i;
string s1 = to_string(i); //to_string是库里的
cout << s1 << endl;
int val = stoi(s1); //stoi是库里的
cout << s1 << endl;
}
int main()
{
//TestString1();
//TestString2();
//TestString3();
//TestString4();
//TestString5();
//TestString6();
//TestString7();
//func("hello,world");
//TestString8();
//TestString9();
//TestString10();
//TestString11();
//TestString12();
TestString13();
//对于new的异常捕获
return 0;
}
后记:
●由于作者水平有限,文章难免存在谬误之处,敬请读者斧正,俚语成篇,恳望指教!
——By 作者:新晓·故知
string.h:
test.cpp:
完整源码及注释:
(1)string.h:
#pragma once #define _CRT_SECURE_NO_WARNINGS #include#include #include using namespace std; //模拟实现string //1.先实现一个简单的string,只考虑资源管理深浅拷贝问题 //自定义命名空间,防止与库中的冲突 //namespace my //{ // //先实现一个简单的string,只考虑资源管理深浅拷贝问题 // //暂不考虑增删查改 // class string // { // public: // //构造函数 // string(const char* str) // :_str(new char[strlen(str) + 1]) // { // //不能直接 _str=str; 因为会权限放大 // strcpy(_str, str); //也拷贝了 // } // //深拷贝函数 s2(s1) // string(const string& s) // :_str(new char[strlen(s._str) + 1]) // { // strcpy(_str, s._str); // } // ~string() // { // if (_str) // { // delete[] _str; // } // } // //s1=s3 ——>s1.operator=(&s1,s3) // //赋值重载函数 // string& operator = (const string& s) // { // if (this != &s) //解决s1=s1,自己释放自己的空间 // { // //先删除,再开辟赋值 // //如果new开辟失败,那s1作为原始数据被删除 // // //先保存,再开辟赋值 // char* tmp = new char[strlen(s._str) + 1]; // strcpy(tmp, s._str); // delete[] _str; // _str = tmp; // } // return *this; // } // //c_str是string中的一个函数,具体详见string文档 // //获取等效的字符串 // const char* c_str() const // { // return _str; // } // //重载[] // char& operator[](size_t pos) // { // assert(pos < strlen(_str)); // return _str[pos]; // } // //计算字符串大小 // size_t size() // { // return strlen(_str); // } // // private: // char* _str; // // }; //} // 2.string完善的增删查改和使用的string //namespace my //{ // class string // { // public: // 构造函数 // //string(const char* str) // // :_size(strlen(str)) // // ,_capacity(_size) // //{ // // //要注意初始化顺序,取决于类的声明顺序 // // _str = new char[_capacity + 1]; // // //不能直接 _str=str; 因为会权限放大 // // strcpy(_str, str); //也拷贝了 // //} // 默认构造函数(无参使用的) // //string() // // :_size(0) // // ,_capacity(0) // //{ // // _str = new char[1]; //将_str初始化为空字符串,string库就是这种做法 // // _str[0] = '0'; // //} // // //默认构造函数(全缺省版) // string(const char* str="") // ""、" "均可以,' '是字符 // :_size(strlen(str)) // , _capacity(_size) // { // //要注意初始化顺序,取决于类的声明顺序 // _str = new char[_capacity + 1]; // //不能直接 _str=str; 因为会权限放大 // strcpy(_str, str); //也拷贝了 // } // 深拷贝函数版本1 s2(s1) // //string(const string& s) // // :_str(new char[strlen(s._str) + 1]) // //{ // // strcpy(_str, s._str); // //} // //深拷贝函数版本2 s2(s1) // string(const string& s) // :_size(strlen(s._str)) // ,_capacity(_size) // { // _str=new char[_capacity + 1]; // strcpy(_str, s._str); // } // // //析构函数 // ~string() // { // if (_str) // { // delete[] _str; // } // } // //s1=s3 ——>s1.operator=(&s1,s3) // //赋值重载函数 // string& operator = (const string& s) // { // if (this != &s) //解决s1=s1,自己释放自己的空间 // { // //先保存,再开辟赋值 // char* tmp = new char[s._capacity + 1]; // strcpy(tmp, s._str); // delete[] _str; // _str = tmp; // _size = s._size; // _capacity = s._capacity; // } // return *this; // } // //c_str是string中的一个函数,具体详见string文档 // //获取等效的字符串 // const char* c_str() const // { // return _str; // } // //重载[] // char& operator[](size_t pos) // { // assert(pos < _size); // return _str[pos]; // } // //重载[] const 提供两个版本的重载[] ,普通对象和const对象都可以调用 // const char& operator[](size_t pos) const // { // assert(pos < _size); // return _str[pos]; // } // //计算字符串大小 // //size_t size(const string* this) // size_t size() const // { // return _size; // } // // size_t capacity() const // { // return _capacity; // } // 尾插数据 // //void push_back(char ch) // //{ // // if (_size == _capacity) //其实为_capacity开辟的多一个为 存储的空间,但那个不参与比较 // // { // // char* tmp = new char[_capacity * 2 + 1]; // // strcpy(tmp, _str); // // delete[] _str; // // _str = tmp; // // _capacity *= 2; // // } // // _str[_size] = ch; // // ++_size; // // _str[_size] = ' '; // //} // // //尾插也可以使用+=(附用push_back) // string& operator+=(char ch) // { // push_back(ch); // return *this; // } // //预留扩容 // void reserve(size_t n) // { // if (n > _capacity) // { // char* tmp = new char[n + 1]; // strcpy(tmp, _str); // delete[] _str; // _str = tmp; // _capacity = n; // } // } // //尾插数据——附用reserve // void push_back(char ch) // { // //if (_size == _capacity) //其实为_capacity开辟的多一个为 存储的空间,但那个不参与比较 // //{ // // //reserve( _capacity * 2);若_capacity为0,则出现bug // // reserve(_capacity==0 ? 4 : _capacity * 2); // //} // //_str[_size] = ch; // //++_size; // //_str[_size] = ' '; // // //附用insert // insert(_size, ch); // } // //追加到字符 // void append(const char*str) // { // // //附用insert // insert(_size, str); // } // //尾插也可以使用+=(附用append) // string& operator+=(const char* str) // { // append(str); // return *this; // } // //扩空间+初始化 // //删除部分数据,保留前n个 // void resize(size_t n, char ch = ' ') // { // //考虑到内存对齐,可能开辟的空间与n有些许微小出入 // if (n < _size) // { // _size = n; // _str[_size] = ' '; // } // else // { // if (n > _capacity) // { // reserve(n); // } // for (size_t i = _size; i < n; ++i) // { // _str[i] = ch; // } // _size = n; // _str[_size] = ' '; // } // } // // //迭代器 // typedef char* iterator; // typedef const char* const_iterator; // // iterator begin() // { // return _str; // } // iterator end() // { // return _str + _size; // } // const_iterator begin() const // { // return _str; // } // const_iterator end() const // { // return _str + _size; // } // //头插数据 // //持续头插,不如尾插逆置 // //插入字符 // string& insert(size_t pos, char ch) // { // assert(pos <= _size); //pos = _size相当于尾插 // if (_size == _capacity) // { // reserve(_capacity == 0 ? 4 : _capacity * 2); // } // //size_t end = _size; // //while (end >= pos) //--end会造成负数,而--end是size_t类型 // //{ // // _str[end + 1] = _str[end]; // // --end; // //} // 解决1:强转类型 // //int end = _size; // //while (end >=(int) pos) //--end会造成负数,而--end是size_t类型 // //{ // // _str[end + 1] = _str[end]; // // --end; // //} // //解决2:修改end位置 // size_t end = _size+1; // while (end > pos) //end等于0就停止 // { // _str[end ] = _str[end-1]; // --end; // } // _str[pos] = ch; // _size ++; // return *this; // } // //插入字符串 // string& insert(size_t pos,const char* str) // { // assert(pos <= _size); // size_t len=strlen(str); // if (_size + len > _capacity) // { // reserve(_size + len); // } // size_t end = _size + len; // while (end > pos + len - 1) //或者while (end >= pos + len) ,但pos、len均为0就有问题 // { // _str[end] = _str[end - len]; // --end; // } // strncpy(_str + pos, str, len); //不能使用strcpy // _size += len; // return *this; // } // //删除 // string& erase(size_t pos, size_t len=npos) // { // assert(pos < _size); // if (len == npos || pos + len >= _size) // { // _str[pos] = ' '; // _size = pos; // } // else // { // size_t begin = pos + len; // while (begin <= _size) // { // _str[begin - len] = _str[begin]; // ++begin; // } // _size -= len; // } // return *this; // } // //查找字符 // //The position of the first character of the first match. // //If no matches were found, the function returns string::npos. // size_t find(char ch,size_t pos=0) // { // for (; pos < _size; ++pos) // { // if (_str[pos] == ch) // { // return pos; // } // } // return npos; // } // //查找字符串 // size_t find(const char*str, size_t pos = 0) // { // const char* p = strstr(_str + pos, str); //strstr暴力算法 // if (p == nullptr) // { // return npos; // } // else // { // return p - _str; // } // } // void clear() // { // _str[0] = ' '; // _size = 0; // } // private: // char* _str; // size_t _size; //有效字符个数,不包含 // size_t _capacity; //实际存储的有效字符的空间 // const static size_t npos; // // }; // //定义 // const size_t string::npos = -1; // //这里不是成员函数,不在类里 // //运算符<重载 // bool operator<(const string& s1, const string& s2) // { // return strcmp(s1.c_str(), s2.c_str()) < 0; // } // //运算符==重载 // bool operator==(const string& s1, const string& s2) // { // return strcmp(s1.c_str(), s2.c_str()) == 0; // } // //运算符<=重载 // bool operator<=(const string& s1, const string& s2) // { // return s1 < s2 || s1 == s2; // } // //运算符>重载 (附用<=实现) // bool operator>(const string& s1, const string& s2) // { // return !(s1 <= s2); // } // //运算符>=重载 (附用<实现) // bool operator>=(const string& s1, const string& s2) // { // return !(s1 < s2); // } // //运算符!=重载 (附用==实现) // bool operator!=(const string& s1, const string& s2) // { // return !(s1 == s2); // } // //流运算符重载 // ostream& operator<<(ostream& out, const string& s) // { // //out << s.c_str(); //无法打印不可见字符 // for (auto ch : s) // { // out << ch; // } // return out; // } // istream& operator>>(istream& in, string& s) // { // //s.clear(); // //char ch; // in >> ch; // //ch = in.get(); // //while (ch != ' ' && ch != 'n') // //{ // // s += ch; // // //in >> ch; // // ch = in.get(); // //} // //return in; // //优化 // s.clear(); // char ch; // ch = in.get(); // char buff[128] = { ' ' }; // size_t i = 0; // while (ch != ' ' && ch != 'n') // { // buff[i++] = ch; // if (i == 127) // { // s += buff; // memset(buff, ' ', 128); // i = 0; // } // ch = in.get(); // } // s += buff; // return in; // } // //getline // //} //3.string完善的增删查改和使用的string(现代写法) namespace my { class string { public: 构造函数 //string(const char* str) // :_size(strlen(str)) // ,_capacity(_size) //{ // //要注意初始化顺序,取决于类的声明顺序 // _str = new char[_capacity + 1]; // //不能直接 _str=str; 因为会权限放大 // strcpy(_str, str); //也拷贝了 //} 默认构造函数(无参使用的) //string() // :_size(0) // ,_capacity(0) //{ // _str = new char[1]; //将_str初始化为空字符串,string库就是这种做法 // _str[0] = '0'; //} //默认构造函数(全缺省版) string(const char* str = "") // ""、" "均可以,' '是字符 :_size(strlen(str)) , _capacity(_size) { //要注意初始化顺序,取决于类的声明顺序 _str = new char[_capacity + 1]; //不能直接 _str=str; 因为会权限放大 strcpy(_str, str); //也拷贝了 } 深拷贝函数版本1 s2(s1) //string(const string& s) // :_str(new char[strlen(s._str) + 1]) //{ // strcpy(_str, s._str); //} 深拷贝函数版本2 s2(s1) //传统写法:本分实现,自劳 //string(const string& s) // :_size(strlen(s._str)) // , _capacity(_size) //{ // _str = new char[_capacity + 1]; // strcpy(_str, s._str); //} //深拷贝函数版本3 s2(s1) //现代写法:剥削行为,借他人之手,行私利,但简单 //tmp去调用构造函数:s1->s2:构造函数->拷贝构造函数->构造函数->swap //tmp->s2 void swap(string& s) { //库里的swap,可交换任意类型 std::swap(_str, s._str); std::swap(_size, s._size); std::swap(_capacity, s._capacity); } string(const string& s) :_str(nullptr) , _size(0) , _capacity(0) { string tmp(s._str); //tmp是局部对象,出作用域会调用析构函数 swap(tmp); } //析构函数 ~string() { if (_str) { delete[] _str; } } //s1=s3 ——>s1.operator=(&s1,s3) 赋值重载函数--版本1 传统写法 //string& operator = (const string& s) //{ // if (this != &s) //解决s1=s1,自己释放自己的空间 // { // //先保存,再开辟赋值 // char* tmp = new char[s._capacity + 1]; // strcpy(tmp, s._str); // delete[] _str; // _str = tmp; // _size = s._size; // _capacity = s._capacity; // } // return *this; //} 赋值重载函数--版本2 现代写法 //string& operator = (const string& s) //{ // if (this != &s) //解决s1=s1,自己释放自己的空间 // { // string tmp(s._str); // swap(tmp); // } // return *this; //} 赋值重载函数--版本3 现代写法 string& operator = (string s) //传值传参,引用返回 { swap(s); return *this; } //c_str是string中的一个函数,具体详见string文档 //获取等效的字符串 const char* c_str() const { return _str; } //重载[] char& operator[](size_t pos) { assert(pos < _size); return _str[pos]; } //重载[] const 提供两个版本的重载[] ,普通对象和const对象都可以调用 const char& operator[](size_t pos) const { assert(pos < _size); return _str[pos]; } //计算字符串大小 //size_t size(const string* this) size_t size() const { return _size; } size_t capacity() const { return _capacity; } 尾插数据 //void push_back(char ch) //{ // if (_size == _capacity) //其实为_capacity开辟的多一个为 存储的空间,但那个不参与比较 // { // char* tmp = new char[_capacity * 2 + 1]; // strcpy(tmp, _str); // delete[] _str; // _str = tmp; // _capacity *= 2; // } // _str[_size] = ch; // ++_size; // _str[_size] = ' '; //} //尾插也可以使用+=(附用push_back) string& operator+=(char ch) { push_back(ch); return *this; } //预留扩容 void reserve(size_t n) { if (n > _capacity) { char* tmp = new char[n + 1]; strcpy(tmp, _str); delete[] _str; _str = tmp; _capacity = n; } } //尾插数据——附用reserve void push_back(char ch) { //if (_size == _capacity) //其实为_capacity开辟的多一个为 存储的空间,但那个不参与比较 //{ // //reserve( _capacity * 2);若_capacity为0,则出现bug // reserve(_capacity==0 ? 4 : _capacity * 2); //} //_str[_size] = ch; //++_size; //_str[_size] = ' '; //附用insert insert(_size, ch); } //追加到字符 void append(const char* str) { //附用insert insert(_size, str); } //尾插也可以使用+=(附用append) string& operator+=(const char* str) { append(str); return *this; } //扩空间+初始化 //删除部分数据,保留前n个 void resize(size_t n, char ch = ' ') { //考虑到内存对齐,可能开辟的空间与n有些许微小出入 if (n < _size) { _size = n; _str[_size] = ' '; } else { if (n > _capacity) { reserve(n); } for (size_t i = _size; i < n; ++i) { _str[i] = ch; } _size = n; _str[_size] = ' '; } } //迭代器 typedef char* iterator; typedef const char* const_iterator; iterator begin() { return _str; } iterator end() { return _str + _size; } const_iterator begin() const { return _str; } const_iterator end() const { return _str + _size; } //头插数据 //持续头插,不如尾插逆置 //插入字符 string& insert(size_t pos, char ch) { assert(pos <= _size); //pos = _size相当于尾插 if (_size == _capacity) { reserve(_capacity == 0 ? 4 : _capacity * 2); } //size_t end = _size; //while (end >= pos) //--end会造成负数,而--end是size_t类型 //{ // _str[end + 1] = _str[end]; // --end; //} 解决1:强转类型 //int end = _size; //while (end >=(int) pos) //--end会造成负数,而--end是size_t类型 //{ // _str[end + 1] = _str[end]; // --end; //} //解决2:修改end位置 size_t end = _size + 1; while (end > pos) //end等于0就停止 { _str[end] = _str[end - 1]; --end; } _str[pos] = ch; _size++; return *this; } //插入字符串 string& insert(size_t pos, const char* str) { assert(pos <= _size); size_t len = strlen(str); if (_size + len > _capacity) { reserve(_size + len); } size_t end = _size + len; while (end > pos + len - 1) //或者while (end >= pos + len) ,但pos、len均为0就有问题 { _str[end] = _str[end - len]; --end; } strncpy(_str + pos, str, len); //不能使用strcpy _size += len; return *this; } //删除 string& erase(size_t pos, size_t len = npos) { assert(pos < _size); if (len == npos || pos + len >= _size) { _str[pos] = ' '; _size = pos; } else { size_t begin = pos + len; while (begin <= _size) { _str[begin - len] = _str[begin]; ++begin; } _size -= len; } return *this; } //查找字符 //The position of the first character of the first match. //If no matches were found, the function returns string::npos. size_t find(char ch, size_t pos = 0) { for (; pos < _size; ++pos) { if (_str[pos] == ch) { return pos; } } return npos; } //查找字符串 size_t find(const char* str, size_t pos = 0) { const char* p = strstr(_str + pos, str); //strstr暴力算法 if (p == nullptr) { return npos; } else { return p - _str; } } void clear() { _str[0] = ' '; _size = 0; } private: char* _str; size_t _size; //有效字符个数,不包含 size_t _capacity; //实际存储的有效字符的空间 const static size_t npos; }; //定义 const size_t string::npos = -1; //这里不是成员函数,不在类里 //运算符<重载 bool operator<(const string& s1, const string& s2) { return strcmp(s1.c_str(), s2.c_str()) < 0; } //运算符==重载 bool operator==(const string& s1, const string& s2) { return strcmp(s1.c_str(), s2.c_str()) == 0; } //运算符<=重载 bool operator<=(const string& s1, const string& s2) { return s1 < s2 || s1 == s2; } //运算符>重载 (附用<=实现) bool operator>(const string& s1, const string& s2) { return !(s1 <= s2); } //运算符>=重载 (附用<实现) bool operator>=(const string& s1, const string& s2) { return !(s1 < s2); } //运算符!=重载 (附用==实现) bool operator!=(const string& s1, const string& s2) { return !(s1 == s2); } //流运算符重载 ostream& operator<<(ostream& out, const string& s) { //out << s.c_str(); //无法打印不可见字符 for (auto ch : s) { out << ch; } return out; } istream& operator>>(istream& in, string& s) { //s.clear(); //char ch; in >> ch; //ch = in.get(); //while (ch != ' ' && ch != 'n') //{ // s += ch; // //in >> ch; // ch = in.get(); //} //return in; //优化 s.clear(); char ch; ch = in.get(); char buff[128] = { ' ' }; size_t i = 0; while (ch != ' ' && ch != 'n') { buff[i++] = ch; if (i == 127) { s += buff; memset(buff, ' ', 128); i = 0; } ch = in.get(); } s += buff; return in; } //getline } //类型转换函数 //atoi C //itoa C //stoi C++11 //to_string
(2)test.cpp:
#include "string.h" //1.基本初始化测试 void TestString1() { my::string s1("hello,world"); cout << s1.c_str() << endl; //修改测试 s1[0] = 'x'; //s1.operator[](0)='x'; cout << s1.c_str() << endl; //读取测试 for (size_t i = 0; i < s1.size(); ++i) { cout << s1[i] << " "; } cout << endl; } //2.浅拷贝及其问题测试 void TestString2() { //浅拷贝带来的问题: //1.析构两次,程序崩溃 2.修改一个值,另一个也被改变 my::string s1("hello,world"); my::string s2(s1); //调用拷贝构造函数 cout << s1.c_str() << endl; cout << s2.c_str() << endl; } //3.深拷贝测试 void TestString3() { //深拷贝:使得值相同,空间大小相同,但空间地址不同 my::string s1("hello,world"); my::string s2(s1); //调用深拷贝构造函数 cout << s1.c_str() << endl; cout << s2.c_str() << endl; s1[0] = 'x'; cout << s1.c_str() << endl; cout << s2.c_str() << endl; } //4.赋值重载测试 void TestString4() { //赋值面临的问题与浅拷贝相似 my::string s1("hello,world"); my::string s2(s1); //调用深拷贝构造函数 my::string s3("qqqqqqqqqq"); s1 = s3; //赋值 cout << s1.c_str() << endl; cout << s2.c_str() << endl; cout << s3.c_str() << endl; } //int main() //{ // //TestString1(); // //TestString2(); // //TestString3(); // TestString4(); // //对于new的异常捕获 // try // { // TestString4(); // } // catch (const exception& e) // { // cout << e.what() << endl; // } // return 0; //} //5.增删查改测试 void TestString5() { my::string s1("hello,world"); cout << s1.c_str() << endl; my::string s2; cout << s2.c_str() << endl; } //6.尾插测试+扩容测试 void TestString6() { //my::string s1("hello,world"); //cout << s1.c_str() << endl; 使用push_back //s1.push_back('y'); //cout << s1.c_str() << endl; //s1.push_back('y'); //cout << s1.c_str() << endl; 使用重载+= (附用push_back) //s1 += '6'; //s1 += '7'; //s1 += '8'; //cout << s1.c_str() << endl; 使用重载+= (附用reserve) //s1 += 'a'; //s1 += 'b'; //s1 += 'c'; //cout << s1.c_str() << endl; //my::string s2; //reserve解决空串_capacity=0,再去_capacity*2仍为0 //s2.reserve(20); //直接开辟指定空间 //库里的string::resize std::string s3("cplusplus"); s3.resize(20, 'x'); s3.resize(5, 'x'); cout << s3 << endl; //模拟实现的string::resize my::string s4("stringtest"); s4.resize(5, 'y'); s4.resize(15, 'g'); cout << s4.c_str() << endl; } //7.遍历测试 void TestString7() { my::string s1("hello,world"); //方式1:下标+[] for (size_t i = 0; i < s1.size(); ++i) { s1[i] += 1; cout << s1[i] << " "; } cout << endl; //方式2:迭代器 my::string::iterator it = s1.begin(); while (it != s1.end()) { *it -= 1; cout << *it << " "; ++it; } cout << endl; //方式3:范围for——底层被替换成迭代器访问 for (auto& ch : s1) { cout << ch << " "; ch += 1; } cout << endl; for (auto ch : s1) { cout << ch << " "; } cout << endl; } //const对象权限测试 void func(const my::string& s) //string的拷贝是深拷贝,使用引用减少拷贝 { //方式1:下标+[] for (size_t i = 0; i < s.size(); ++i) { //s[i] += 1; //这里传给const形参,不能写 cout << s[i] << " "; } cout << endl; //方式2:迭代器 my::string::const_iterator it = s.begin(); while (it != s.end()) { / my::string s4("hello,world"); cin >> s4; cout << s4 << endl; } //12.赋值重载测试 void TestString12() { my::string s1("hello,world"); my::string s2(s1); cout << s2<< endl; my::string s3; s3 = s1; cout << s3 << endl; } //13.转换函数测试 void TestString13() { int i; cin >> i; string s1 = to_string(i); //to_string是库里的 cout << s1 << endl; int val = stoi(s1); //stoi是库里的 cout << s1 << endl; } int main() { //TestString1(); //TestString2(); //TestString3(); //TestString4(); //TestString5(); //TestString6(); //TestString7(); //func("hello,world"); //TestString8(); //TestString9(); //TestString10(); //TestString11(); //TestString12(); TestString13(); //对于new的异常捕获 return 0; }
●由于作者水平有限,文章难免存在谬误之处,敬请读者斧正,俚语成篇,恳望指教!
——By 作者:新晓·故知