前段时间看了点东西,导致知识比较乱,最近打算把他们总结一下,首先就是C/C++的string。首先简单的回顾接口之后还将讨论一下深浅拷贝的问题。
string
C的函数库里也提供了很多对C风格字符串操作的函数,但是使用的时候还是会遇到很多问题内存泄漏,访问越界,覆盖等一系列的问题,而且还不符合面向对象的风格。所以C++引入了字符串类。
string的接口
这里我们主要列出修改字符串的接口:
有空了在写,自己查c++也可
resize() 和 reserve()的区别
reserve是容器预留空间,但并不真正创建元素对象,在创建对象之前,不能引用容器内的元素,因此当加入新的元素时,需要用push_back()/insert()函数。
resize是改变容器的大小,并且创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。
再者,两个函数的形式是有区别的,reserve函数之后一个参数,即需要预留的容器的空间;resize函数可以有两个参数,第一个参数是容器新的大小,第二个参数是要加入容器中的新元素,如果这个参数被省略,那么就调用元素对象的默认构造函数。
深浅拷贝
浅拷贝 —-只是拷贝了基本类型的数据,而引用类型数据,复制后也是会发生引用,我们把这种拷贝叫做“(浅复制)浅拷贝”,换句话说,浅复制仅仅是指向被复制的内存地址,如果原地址中对象被改变了,那么浅复制出来的对象也会相应改变。
深拷贝 —-在计算机中开辟了一块新的内存地址用于存放复制的对象。
实现String类
这里有一种现代写法,因为String是深拷贝所以,所以设计临界资源的管理。现代写法利用局部变量的声明周期解决了这方面的问题。下面给出实现:
#include <assert.h>
class String
{
public:
typedef char* iterator;
typedef const char* const_iterator;
const_iterator begin() const
{
return _str;
}
const_iterator end() const
{
return _str + _size;
}
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
String(const char* str = "")
:_str(nullptr)
, _capacity(0)
{
_size = strlen(str);
Reserve(_size);
strcpy(_str, str);
}
// s2(s1)
String(const String& s)
:_str(nullptr)
, _size(0)
, _capacity(0)
{
String tmp(s._str);
Swap(tmp); // tmp.Swap(*this);
}
// s1 = s3
String& operator=(String s)
{
Swap(s);
return *this;
}
// s1.Swap(s2)
void Swap(String& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
~String()
{
if (_str)
{
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
}
void PushBack(char ch)
{
/*if (_size == _capacity)
{
Reserve(_capacity * 2);
}
_str[_size] = ch;
++_size;
_str[_size] = '\0';*/
Insert(_size, ch);
}
void Append(const char* str)
{
/* size_t len = strlen(str);
if (_size + len > _capacity)
{
Reserve(_size + len);
}
strcpy(_str + _size, str);
_size += len;*/
Insert(_size, str);
}
// s1 += 'c'
String& operator+=(char ch)
{
PushBack(ch);
return *this;
}
String& operator+=(const char* str)
{
Append(str);
return *this;
}
void Insert(size_t pos, char ch)
{
assert(pos <= _size);
if (_size == _capacity)
{
Reserve(_capacity * 2);
}
for (size_t i = _size; i >= pos; --i)
{
_str[i + 1] = _str[i];
}
_str[pos] = ch;
_size++;
}
void Insert(size_t pos, const char* str);
void Erase(size_t pos = 0, size_t len = npos);
size_t Find(char ch, size_t pos = 0);
size_t Find(const char* str, size_t pos = 0);
bool operator<(const String& s)const;
bool operator<=(const String& s)const;
bool operator>(const String& s)const;
bool operator>=(const String& s)const;
bool operator==(const String& s)const;
bool operator!=(const String& s)const;
// s1 + 'c'
String operator+(char ch) const
{
String tmp(*this);
tmp.PushBack(ch);
return tmp;
}
String& operator+(const char* str)
{
String tmp(*this);
tmp.Append(str);
return tmp;
}
char* c_str() const
{
return _str;
}
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
const char& operator[](size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
size_t Size() const
{
return _size;
}
size_t Capacity() const
{
return _capacity;
}
void Reserve(size_t n)
{
if (n == 0 || n > _capacity)
{
//size_nt ewsize = (n + 7) & ( ~7);
size_t newsize = n;
if (n % 8 != 0)
newsize = (n / 8 + 1) * 8;
else
newsize = n + 8;
char* newstr = new char[newsize];
if (_str)
strcpy(newstr, _str);
_str = newstr;
_capacity = newsize - 1;
}
}
void Resize(size_t n, char ch = '\0')
{
if (n <= _size)
{
_size = n;
_str[_size] = '\0';
}
else
{
Reserve(n);
for (size_t i = _size; i < n; ++i)
{
_str[i] = ch;
++_size;
}
_str[_size] = '\0';
}
}
private:
char* _str;
size_t _size;
size_t _capacity;
static size_t npos;
};
size_t String::npos = -1;