1.2 string類的常見接口說明
字符串是表示字符序列的類
成都創(chuàng)新互聯(lián)長期為上千多家客戶提供的網站建設服務,團隊從業(yè)經驗10年,關注不同地域、不同群體,并針對不同對象提供差異化的產品和服務;打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網生態(tài)環(huán)境。為凌云企業(yè)提供專業(yè)的做網站、成都網站設計,凌云網站改版等技術服務。擁有10余年豐富建站經驗和眾多成功案例,為您定制開發(fā)。標準的字符串類提供了對此類對象的支持,其接口類似于標準字符容器的接口,但添加了專門用于操作單字節(jié)字符字符串的設計特性。
string類是使用char(即作為它的字符類型,使用它的默認char_traits和分配器類型(關于模板的更多信息,請參閱basic_string)。
string類是basic_string模板類的一個實例,它使用char來實例化basic_string模板類,并用char_traits和allocator作為basic_string的默認參數(shù)(根于更多的模板信息請參考basic_string)。
注意,這個類獨立于所使用的編碼來處理字節(jié):如果用來處理多字節(jié)或變長字符(如UTF-8)的序列,這個類的所有成員(如長度或大小)以及它的迭代器,將仍然按照字節(jié)(而不是實際編碼的字符)來操作。
總結:
string是表示字符串的字符串類
該類的接口與常規(guī)容器的接口基本相同,再添加了一些專門用來操作string的常規(guī)操作
string在底層實際是:basic_string模板類的別名,typedef basic_string
string; 不能操作多字節(jié)或者變長字符的序列。
2. string模擬實現(xiàn)
函數(shù)名稱 功能說明 string() 構造空string類對象,即空字符串 string(const char* s) 用C-string來構造string類對象 string(size_t n, char c) string類對象中包含n個字符c string(const string& s) 拷貝構造 void test() { string s1;//構造空的string類對象s1 string s2("hello yhh");//用C-string來構造string類對象 string s3(s2);//拷貝構造s3 string s4(8, 'a');//string類對象中含有n個字符C }
- string類對象的容器操作
函數(shù)名稱 共能說明 size 返回字符串有效字符長度 length 返回字符串有效字符長度 capacity 返回空間總大小 empty 檢測字符串是否為空串,是返回true,否則返回false clear 清空有效字符 reserve 為字符串預留空間,不初始化 resize 將有效字符的個數(shù)改成n個,多出空間用字符C填充,要初始化 注意:
size()與length()方法底層實現(xiàn)原理完全相同,引入size()的原因是為了與其他容器的接口保持一
致,一般情況下基本都是用size()。clear()只是將string中有效字符清空,不改變底層空間大小
. resize(size_t n) 與 resize(size_t n, char c)都是將字符串中有效字符個數(shù)改變到n個,不同的是當字符個數(shù)增多時:resize(n)用0來填充多出的元素空間,resize(size_t n, char c)用字符c來填充多出的元素空間。注意:resize在改變元素個數(shù)時,如果是將元素個數(shù)增多,可能會改變底層容量的大小,如果是將元素個數(shù)減少,底層空間總大小不變。
reserve(size_t res_arg=0):為string預留空間,不改變有效元素個數(shù),當reserve的參數(shù)小于
string的底層空間總大小時,reserve不會改變容量大小容量是變大不小
string類對象的訪問及遍歷操作
函數(shù)名稱 功能說明 operator[] 返回pos位置的字符,const string類對象調用 begin+end begin獲取一個字符的迭代器 + end獲取最后一個字符下一個位置的迭 代器 rend + rbegin begin獲取一個字符的迭代器 + end獲取最后一個字符下一個位置的迭 代器 范圍for C++11支持更簡潔的范圍for的新遍歷方式 string類對象的修改操作
函數(shù)名稱 功能說明 push_back 在字符串后尾插字符c append 在字符串后追加一個字符串 operator+= 在字符串后追加字符串str c_str 返回C格式字符串 find + npos 從字符串pos位置開始往后找字符c,返回該字符在字符串中的位置(找不到返回npos) rfind 從字符串pos位置開始往前找字符c,返回該字符在字符串中的位置 substr 在str中從pos位置開始,截取n個字符,然后將其返回 注意:
在string尾部追加字符時,s.push_back? / s.append(1, c) / s += 'c’三種的實現(xiàn)方式差不多,一般情況下string類的+=操作用的比較多,+=操作不僅可以連接單個字符,還可以連接字符串。
對string操作時,如果能夠大概預估到放多少字符,可以先通過reserve把空間預留好
string類非成員函數(shù)
函數(shù) 功能說明 operator+ 盡量少用,因為傳值返回,導致深拷貝效率低 operator>> 輸入運算符重載 operator<< 輸出運算符重載 getline 獲取一行字符串 relational operators 大小比較
namespace yhh
{
class string
{
public:
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
return _str;
}
iterator end()
{
return _size + _str;
}
const iterator begin() const
{
return _str;
}
const iterator end() const
{
return _size + _str;
}
size_t size() const
{
return _size;
}
size_t capacity()const
{
return _capacity;
}
char* c_str() const
{
return _str;
}
string(const char* str = "")
{
_size = strlen(str);
_capacity = _size;
_str = new char[_capacity + 1];//留給'/0'
strcpy(_str, str);
}//構造函數(shù),初始話列表按照聲明的順序初始話
//傳統(tǒng)寫法
//string(const string& s)
// :_str(new char[s._capacity+1])
// ,_size(s._size)
// ,_capacity(s._capacity)
//{
// strcpy(_str, s._str);
//}
//string& operator=(const string& s)//賦值會把原來的值干掉
//{
// if (&s != this)
// {
// //delete[] _str;
// //_str = new char[s._capacity + 1];//如果new失敗,就把原對象破壞了
// //strcpy(_str, s._str);
// char* tmp = new char[s._capacity + 1];
// strcpy(tmp, s._str);
// delete[] _str;
// _str = tmp;
// _size = s._size;
// _capacity = s._capacity;
// }
// return *this;
//}
//現(xiàn)代寫法
void swap(string& tmp)
{
::swap(_str, tmp._str);//去全局域去找
::swap(_size, tmp._size);
::swap(_capacity, tmp._capacity);
}
string(const string& str)
:_str(nullptr)
, _size(0)
, _capacity(0)
{
string tmp(str._str);
swap(tmp);
}//拷貝構造
string& operator=(const string& str)
{
if (this != &str)
{
string tmp(str._str);//tmp局部對象出了作用域調用析構函數(shù),釋放this指向的那個
swap(tmp);
}
return *this;
}// 賦值
//string& operator=(string str)
//{
// swap(str);
// return *this;
//}//賦值, 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];
}
void reserve(size_t n)
{
if (n >_capacity)
{
char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
void resize(size_t n, char ch = '\0')
{
if (n >_size)
{
reserve(n);
for (size_t i = _size; i< n; i++)
{
_str[i] = ch;
}
_str[n] = '\0';
_size = n;
}
else
{
_str[n] = '\0';
_size = n;
}
}//多了刪除數(shù)據(jù),少了就在結尾添加'\0'
void push_back(char ch)
{
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : _capacity * 2);
}
_str[_size] = ch;//添加元素
_size++;
_str[_size] = '\0';//添加結尾
}
void append(const char* str)
{
size_t len = strlen(str);
if (_size + len >_capacity)
{
reserve(_size + len);
}//可以不要這個if,但是就會多幾次函數(shù)調用,如果不需要開辟空間的話
//aa bb
strcpy(_str + _size, str);//在結尾追加
_size += len;
}
void append(const string& s)
{
append(s._str);
}
void append(size_t n, char ch)
{
reserve(_size + n);
for (size_t i = 0; i< n; ++i)
{
push_back(ch);
}
}
string& operator+=(const char* s)
{
append(s);
return *this;
}
string& operator+=(const char ch)
{
push_back(ch);
return *this;
}
string& insert(size_t pos, char ch)
{
assert(pos<= _size);
if (_capacity == _size)
{
reserve(_capacity == 0 ? 4 : _capacity * 2);
}
size_t end = _size + 1;
while (end >pos)
{
_str[end] = _str[end - 1];
--end;
}
_str[pos] = ch;
_size++;
return *this;
}
string& insert(size_t pos, const char* str)
{
assert(pos<= _size);
int len = strlen(str);
if (len + _size >_capacity)
{
reserve(_size + len);
}
size_t end = _size + len;//把前一個的'/0'也拷貝走防止,在_size插入出現(xiàn)錯誤
while (end >= pos + len)
{
_str[end] = _str[end - len];
end--;
}//因為插入了字符串就不會讓end小于0
strncpy(_str + pos, str, len);
_size += len;
return *this;
}
string& erase(size_t pos, size_t len = npos)
{
assert(pos< _size);
if (len == npos || len + pos >= _size)
{
_str[pos] = '\0';
_size = pos;
}
else
{
strcpy(_str + pos, _str + pos + len);
_size -= len;
}
return *this;
}
void clear()
{
_size = 0;
_str[0] = '\0';
}
size_t find(char ch, size_t pos = 0)const
{
assert(pos< _size);
for (size_t i = pos; i< _size; i++)
{
if (ch == _str[i])
return i;
}
return npos;
}
size_t find(const char* sub, size_t pos = 0)const//找子串
{
assert(sub);
assert(pos< _size);
// kmp/bm
const char* ptr = strstr(_str + pos, sub);
if (ptr == nullptr)
{
return npos;
}
else
{
return ptr - _str;
}
}
//size_t find(const char* s, size_t pos = 0) const
//{
// assert(s);
// assert(pos< _size);
// const char* src = _str + pos;
// while (*src)
// {
// const char* tmp = src;
// const char* match = s;
// while (*match == *tmp && *match && *tmp)
// {
// match++;
// tmp++;
// }
// if (*match == '\0')
// {
// return src - _str;
// }
// else
// {
// src++;
// }
// }
// return npos;
//}
string substr(size_t pos, size_t len = npos) const
{
assert(pos< _size);
size_t realLen = len;
if (len == npos || pos + len >_size)
{
realLen = _size - pos;
}
string sub;
for (size_t i = 0; i< realLen; ++i)
{
sub += _str[pos + i];
}
return sub;
}//獲得_str中的字串,而且是新開辟的空間
bool operator<(const string& s)const
{
return strcmp(_str, s._str)< 0;
}
bool operator>(const string& s)const
{
return !(*this<= s);
}
bool operator>=(const string& s)const
{
return !(*this< s);
}
bool operator<=(const string& s)const
{
return *this< s || *this == s;
}
bool operator==(const string& s)const
{
return strcmp(_str, s._str) == 0;
}
bool operator!=(const string& s)const
{
return !(*this == s);
}
~string()
{
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}//析構函數(shù)
private:
char* _str;
size_t _size;
size_t _capacity;
public:
static size_t npos;/
};
size_t string::npos = -1;
ostream& operator<<(ostream& out, const string& s)
{
for (size_t i = 0; i< s.size(); i++)
{
cout<< s[i];
}
return out;
}
//istream& operator>>(istream& in, string& s)
//{
// s.clear();
// char ch;
// ch = in.get();
// while (ch != ' ' && ch != '\n')
// {
// size_t old = s.capacity();
// s += ch;
// if (s.capacity() != old)
// {
// cout<< old<< "擴容"<< s.capacity()<< endl;
// }
// ch = in.get();
// }
// return in;
//}
istream& operator>>(istream& in, string& s)
{
s.clear();
char ch;
ch = in.get();
const size_t N = 32;
char buff[N];
size_t i = 0;
while (ch != ' ' && ch != '\n')
{
buff[i++] = ch;
if (i == N - 1)
{
buff[i] = '\0';
s += buff;
i = 0;
}
ch = in.get();
}//類似于緩存器這樣的
buff[i] = '\0';
s += buff;
return in;
}
}
3. 深淺拷貝
3.1 淺拷貝淺拷貝:也稱位拷貝,編譯器只是將對象中的值拷貝過來。如果對象中管理資源,最后就會導致多個對象共享同一份資源,當一個對象銷毀時就會將該資源釋放掉,而此時另一些對象不知道該資源已經被釋放,以為還有效,所以當繼續(xù)對資源進項操作時,就會發(fā)生發(fā)生了訪問違規(guī) 。
3.2 深拷貝說明:上述String類沒有顯式定義其拷貝構造函數(shù)與賦值運算符重載,此時編譯器會合成默認的,當用s1構造s2時,編譯器會調用默認的拷貝構造。最終導致的問題是,s1、s2共用同一塊內存空間,在釋放時同一塊空間被釋放多次而引起程序崩潰,這種拷貝方式,稱為淺拷貝。
4.寫實拷貝每個對象都有一份獨立的資源,不要和其他對象共享。
如果一個類中涉及到資源的管理,其拷貝構造函數(shù)、賦值運算符重載以及析構函數(shù)必須要顯式給出。一般情
況都是按照深拷貝方式提供。
寫時拷貝就是一種拖延癥,是在淺拷貝的基礎之上增加了引用計數(shù)的方式來實現(xiàn)的。
引用計數(shù):用來記錄資源使用者的個數(shù)。在構造時,將資源的計數(shù)給成1,每增加一個對象使用該資源,就給
計數(shù)增加1,當某個對象被銷毀時,先給該計數(shù)減1,然后再檢查是否需要釋放資源,如果計數(shù)為1,說明該
對象時資源的最后一個使用者,將該資源釋放;否則就不能釋放,因為還有其他對象在使用該資源
你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網查看詳情吧