//浅拷贝
String(const String& str)
:_data(str._data)
{}
//深拷贝,拷贝对象的内容和对象的资源
String(const String& str)
:_data(new char[strlen(str._data)+1])
{
strcpy(_data, str._data);
}
浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以 当继续对资源进项操作时,就会发生发生了访问违规。要解决浅拷贝问题,C++中引入了深拷贝。
浅拷贝只是拷贝_data这个指针,深拷贝还会拷贝指针指向的内容“123”。
#include<stdio.h>
#include<iostream>
#include<string>
using namespace std;
class String
{
public:
//构造函数
String(const char* str=" ")
:_data(new char[strlen(str)+1])
{
strcpy(_data, str);
}
//浅拷贝
//String(const String& str)
//:_data(str._data)
//{}
//深拷贝,拷贝对象的内容和对象的资源
String(const String& str)
:_data(new char[strlen(str._data)+1])
{
//拷贝资源
strcpy(_data, str._data);
}
//赋值
String& operator=(const String& str)
{
if (this != &str)
{
//释放原有的资源空间
delete[] _data;
//开辟新的资源空间
_data = new char[strlen(str._data) + 1];
//拷贝内容
strcpy(_data, str._data);
}
return *this;
}
//析构函数
~String()
{
if (_data)
{
delete[] _data;
_data = nullptr;
}
}
private:
char* _data;
};
void test()
{
String str("hello");
String str2("abc");
String copy(str);
//str2要调用string类的拷贝构造函数来构造,这样str2指向的资源和str指向的资源一样
//在调用析构的时候,str2被销毁,str2和str指向的资源也被销毁
//str成为野指针,在销毁str时出错,所以需要显式深拷贝构造函数
str2 = str;//str2是第一个参数被this指针接收,str是第二个参数
//先释放str2的资源,再让str2指向开辟的新的资源空间,再将str的内容拷贝过来
}
以上是传统写法
现代写法:
#include<stdio.h>
#include<iostream>
#include<string>
using namespace std;
class String {
public:
String(const char* str = "")
:_data(new char[strlen(str) + 1])//初始化对象,给对象开辟空间
{
strcpy(_data, str);//把参数中的内容拷贝到对象的_data中来
}
//拷贝构造,现代写法->复用拷贝的逻辑
//借助构造函数在创建局部对象时,进行空间申请和内容拷贝
//通过交换成员的指向达到深拷贝的目的
String(const String& str)
:_data(nullptr)//初始化为nullptr
{
String tmp(str._data);//创建一个新的tmp局部对象
swap(_data, tmp._data);//交换tmp对象和当前对象,即可实现深拷贝
}
~String()
{
if (_data)
{
delete[] _data;
_data = nullptr;
}
}
private:
char* _data;
};
void test()
{
String str = "1234";
String copy(str);
}
int main()
{
test();
return 0;
}
//现代赋值写法: 复用拷贝,借助拷贝构造完成:进行空间申请+内容拷贝
//借用局部对象的析构函数完成当前对象原有资源的释放
String& operator=(String str)//String str创建了一个局部对象
{
swap(_data, str._data);
return *this;
}
int main()
{
String str("123");
String str2("abc");
str2 = str;
}
string类的实现
#include<stdio.h>
#include<iostream>
#include<string>
#include<assert.h>
using namespace std;
class String {
public:
//String的迭代器
//实现:字符指针
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
//第一个元素的位置
return _data;
}
const_iterator begin()const
{
//第一个元素的位置
return _data;
}
iterator end()
{
//最后一个元素的位置
return _data + _size;
}
const_iterator end()const
{
//最后一个元素的位置
return _data + _size;
}
String(const char* str = "")
:_size(strlen(str))
,_capacity(_size)
, _data(new char[_size + 1])
{
strcpy(_data, str);
}
//拷贝构造
String(const String& str)
:_size(0)
,_capacity(0)
,_data(nullptr)//初始化为nullptr
{
String tmp(str._data);//创建一个新的tmp局部对象
Swap(tmp);//交换tmp对象和当前对象,即可实现深拷贝
}
void Swap(String& str)//对象的所有成员都要拷贝
{
swap(_size, str._size);
swap(_capacity, str._capacity);
swap(_data, str._data);
}
//赋值
String& operator=(String str)
{
Swap(str);
return *this;
}
//析构
~String()
{
if (_data)
{
delete[] _data;
_data = nullptr;
_size = _capacity = 0;
}
}
//返回字符个数
size_t size()const
{
return _size;
}
//返回容量
size_t capacity()const
{
return _capacity;
}
char& operator[](size_t pos)//可读可写
{
assert(pos < _size);
return _data[pos];
}
char& operator[](size_t pos)const//只读
{
assert(pos < _size);
return _data[pos];
}
const char* c_str()const
{
return _data;
}
//尾插字符
void pushBack(const char& ch)
{
//没有空余空间
if (_size == _capacity)
{
//增容,2倍
size_t newcap = _capacity == 0 ? 15 : 2 * _capacity;
reserve(newcap);
}
//如果有空余空间
_data[_size] = ch;
++_size;
_data[_size] = '\0';
}
//增加容量
void reserve(size_t n)
{
//只增加容量
if (n > _capacity)
{
//1.开辟一个空间
char* tmp = new char[n+1];//加一是为'\0'留位置
//2.拷贝
strcpy(tmp, _data);
//3.释放原有空间
delete[]_data;
//更新成员
_data = tmp;
_capacity = n;
}
}
void resize(size_t n, const char& ch = '\0')//用‘\0’填充
{
// n > _capacity
if (n > _capacity)
{
//增容
reserve(n);
}
//_size < n <= _capacity,需要填充字符
//for (size_t pos = _size; pos < n; pos++)
//{
//_data[pos] = ch;
//}
if(n>_size)
memset(_data + _size, ch, sizeof(char)*(n - _size));//把剩下的空间全部填充为ch
//当n小于等于_size时
_size = n;
_data[_size] = '\0';
}
//追加字符串
void append(const char* str)
{
//1.检查容量
int len = strlen(str);
if (_size+len > _capacity)
{
//增容
reserve(_size+len);
}
//2.插入
memcpy(_data + _size, str, sizeof(char)*len);//效率更高,一次性拷贝,但不会拷贝\0
//strcpy(_data + _size, str);
//3.更新
_size += len;
_data[_size] = '\0';
}
//operator+=
String& operator+=(const String& str)
{
append(str._data);
return *this;
}
String& operator+=(const char* str)
{
append(str);
return *this;
}
String& operator+=(const char str)
{
pushBack(str);
return *this;
}
//在pos位置插入字符ch
void insert(size_t pos, const char& ch)
{
//位置的检查,位置应该在0-size之间
assert(pos <= _size);//因为pos是无符号类型,所以一定大于等于0
//1.检查容量
if (_size == _capacity)
{
size_t newC = _capacity == 0 ? 15 : 2 * _capacity;
reserve(newC);
}
//2.移动元素,先移动后面的。
size_t end = _size + 1;//最先移动的是'\0'
while (end > pos)
{
_data[end] = _data[end - 1];
end--;
}
//3.插入
_data[pos] = ch;
//更新
_size++;
}
//在pos位置插入字符串ptr
void insert(size_t pos, const char* ptr)
{
//检查位置
assert(pos <= _size);
int len = strlen(ptr);
//检查容量
if (_size+len > _capacity)
{
reserve(_size+len);
}
//移动元素
size_t end = _size + len;
while (end > pos + len - 1)
{
//pos + len pos
_data[end] = _data[end - len];
--end;
}
//插入
memcpy(_data + pos, ptr, sizeof(char)*len);
//更新
_size += len;
}
//删除
void erase(size_t pos, size_t len = npos)
{
assert(pos < _size);
//从pos位置开始,删除剩余的所有元素
if (len == npos||pos +len >= _size)
//如果不传入len参数,则len 和 npos相等,则把剩余元素全删除
//或者要删除的元素大于等于元素的个数
{
_size = pos;
_data[_size] = '\0';
}
else
{//从前向后,每一个待移动的元素统一向前移动len个位置
size_t start = pos + len;
// [pos + len _size]
while (start <= _size)
{
_data[start - len] = _data[start];
++start;
}
_size -= len;
}
}
//查找字符
size_t find(const char& ch, size_t pos = 0)
{
for (size_t i = pos; i < _size; i++)
{
if (_data[i] == ch)
{
return i;
}
}
return npos;
}
//查找字符串
size_t find(const char* ptr, size_t pos = 0)
{
assert(pos < _size);
char* ptrpos = strstr(_data+pos, ptr);
if (ptrpos)
{
return ptrpos - _data;
}
return npos;
}
//从pos位置截取len个字符
String substr(size_t pos, size_t len = npos)
{
assert(pos <= _size);
if (len == npos||pos + len >= _size)
{
String str(_data + pos);
return str;
//return String(_data+pos);
}
else
{
char* newchar = new char[len+1];//动态开辟一个新空间
//char new[len+1];在栈上开辟空间
memcpy(newchar, _data + pos, sizeof(char)*len);//把要移动的字符串复制到这个新空间中
newchar[len] = '\0';
return String(newchar);//创建一个截取字符串的对象并返回
delete[]newchar;
}
}
private:
size_t _size;//有效字符的个数
size_t _capacity;//容量:存放字符的最大个数
char* _data;//先初始化size和capacity,再初始化数据空间
static const size_t npos;
};
const size_t String::npos = -1;//静态变量要在类外初始化
String operator+(const String& str1, const String& str2)
{
String str = str1;
str += str2;
return str;
}
String operator+(const char* str1, const String& str2)
{
String str = str1;
str += str2;
return str;
}
String operator+(const char str1, const String& str2)
{
String str = str2;
str += str1;
return str;
}
bool operator<(const String& str1, const String& str2)
{
int ret = strcmp(str1.c_str(), str2.c_str());
if (ret < 0)
return true;
else
return false;
}
bool operator==(const String& str1, const String& str2)
{
int ret = strcmp(str1.c_str(), str2.c_str());
if (ret == 0)
return true;
else
return false;
}
//输出
ostream& operator<<(ostream& out, const String& str)
{
for (const auto& ch : str)
{
out << ch;
}
return out;
}
//输入
istream& operator>>(istream& in, String& str)
{
char ch;
while ((ch = cin.get())!=EOF)
{
if (ch == ' ' || ch == '\n')
break;
str += ch;
}
return cin;
}
void testout()
{
String str("12345678");
cout << str << str << endl;
}
void testpushback()
{
String str;
str.pushBack('1');
str.pushBack('2');
str.pushBack('3');
for (auto&ch : str)
{
cout << ch << " ";
}
cout << endl;
}
void testfor()
{
char arr[] = "abcdefg";
for (const auto&ch : arr)
{
cout << ch << " ";
}
cout << endl;
//范围for,底层调用迭代器访问
String str = "123456789";
for (auto&ch : str)
{
ch = 'a';
cout << ch << " ";
}
cout << endl;
}
void test()
{
String str = "123456789";
for (size_t i = 0; i < str.size(); i++)
{
cout << str[i] << " ";//简写形式
str[i] = i + 'a';//将每一个元素变为字母
cout << str.operator[](i) << " ";//标准形式
cout << endl;
}
}
void print(const String& str)//不能修改内容,调用的是operator[]只读接口
{
for (size_t i = 0; i < str.size(); i++)
{
cout << str[i] << " ";
}
cout << endl;
}
int main()
{
testpushback();
return 0;
}