目录
一、STL介绍
A.什么是STL
B.STL六个组件
C.STL的缺陷
二、String
A.String介绍
B.String常用接口
1.构造
2.析构
3. String类对象的容量操作
4.String类对象的访问操作
5.string类对象的修改操作
6.非成员函数重载
一、STL介绍
A.什么是STL
STLL(standard template libaray-标准模板库)是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。
B.STL六个组件
C.STL的缺陷
1. STL库的更新太慢了。 2. STL现在都没有支持线程安全。并发环境下需要我们自己加锁。且锁的粒度是比较大的。 3. STL极度的追求效率,导致内部比较复杂。比如类型萃取,迭代器萃取。 4. STL的使用会有代码膨胀的问题,比如使用vector/vector/vector这样会生成多份代码,当然这是模板语法本身导致的。二、String
A.String介绍
1.字符串是表示字符序列的类 2.该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。 3. string在底层实际是:basic_string模板类的别名: typedef basic_stringB.String常用接口
1.构造
string() (重点) | 构造空的 string 类对象,即空字符串 |
string(const char* s) (重点) | 用 C-string(字符串) 来构造 string 类对象 |
string(size_t n, char c) | string 类对象中包含 n 个字符 c |
string(const string&s) (重点) | 拷贝构造函数 |
string (const string& str, size_t pos, size_t len = npos); | 用子字符串构造string对象 |
string (const char* s, size_t n); | 根据字符串的一个序列来构造string对象 |
string (size_t n, char c); | 用连续的字符c填充string对象 |
template | 相同的顺序复制范围[first,last)中的字符序列。 |
string (string&& str) noexcept; | 获取str的内容。 str处于未指定但有效的状态。 简单来说就是想要获取一些数据必须要带上这个括号,例如s.size()、s.capacity()等等 |
2.析构
~string(); 默认析构函数,调用自定义类型的析构函数对内置类型不处理需要我们显示实现。
3. String类对象的容量操作
size (重点) | 返回字符串有效字符长度 |
length | 返回字符串有效字符长度 |
capacity | 返回空间总大小 |
empty (重点) | 检测字符串释放为空串,是返回 true ,否则返回 false |
clear (重点) | 清空有效字符 |
reserve (重点) | 为字符串预留空间 * * |
resize (重点) | 将有效字符的个数该成n个,多出的空间用字符c填充 |
1. size是计算字符串长度,在string类中他的值和用法和length相同 ,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
需要注意的是 空格 也算一个 size的。
2. capacity是返回string所占空间的大小,此容量不一定等于字符串长度。它可以相等或更大,额外的空间允许对象在向字符串添加新字符时优化其操作。
capacity的理论最大值由max_size给出(没什么用)。
3. empty:检测看string是不是空的(看length是否为0),不会对字符串做任何修改。
如果字符串是空的则会返回 true ,不是空的则返回 false。
bool empty() const noexcept;
4. clear:清空有效字符,直到length为0。(erase)
void clear() noexcept;
注意:capacity不会变。
5. reserve:为string对象申请空间 以为了方便将size和length提升到n的操作。
void reserve (size_t n = 0);
注意:reserve只能申请空间,不能删除空间(在reserve中capacity只能增不能减)
reserve过后size不会变。
6. resize:把string对象改成一个size大小为n的对象。
void resize (size_t n); void resize (size_t n, char c);
如果n小于当前的size(length),则当前string将缩短,删除第 n 个字符以外的字符。
如果n大于当前的size(length),则会用我们resize的c字符来重复填充后面的字符串,如果没写c,则会默认填充空字符'0’
// 将s中有效字符个数增加到10个,多出位置用'a'进行填充 // “aaaaaaaaaa” s.resize(10, 'a'); cout << s.size() << endl; cout << s.capacity() << endl; // 将s中有效字符个数增加到15个,多出位置用缺省值'0'进行填充 // "aaaaaaaaaa00000" // 注意此时s中有效字符个数已经增加到15个 s.resize(15); cout << s.size() << endl; cout << s.capacity() << endl; cout << s << endl; // 将s中有效字符个数缩小到5个 s.resize(5); cout << s.size() << endl; cout << s.capacity() << endl; cout << s << endl;
通过上面这串代码我们可知 :
resize在改变size的同时,如果size增大,是会导致capacity增大的,反之,如果导致size减小,那capacity不会变。
4.String类对象的访问操作
operator[ ] ( 重 点) | 返回 pos 位置的字符, const string 类对象调用 |
begin + end | begin 获取一个字符的迭代器 + end 获取最后一个字符下一个位置的迭 代器 |
rbegin 和 rend | begin 获取一个字符的迭代器 + end 获取最后一个字符下一个位置的迭 代器 |
范围 for | C++11支持更简洁的范围for的新遍历方式 |
1.operator [ ]
返回字符串中pos(下标,第一个是0)位置的引用(可读可写)
char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;
注意:1.如果pos等于size,那么会返回'0'的引用
2.如果越界会报错。
另外 , at 也能达到相同的作用:
char& at (size_t pos); const char& at (size_t pos) const;(也是返回pos下标位置的引用),不同的是at会返回异常。需要捕捉。
2.begin和end
string::begin() 获取首字符的迭代器,例如str.begin() + 2,这里给的就是下标为2的字符的迭代器
string::end() 获取最后一个字符的下一个位置的迭代器
先记住迭代器的用法: string::iterator it = str.begin(); 定义一个迭代器,
#include#include int main (){ string str ("Test string"); for (string::iterator it=str.begin(); it!=str.end(); ++it) { cout << *it; } cout << 'n'; return 0;}
begin()和end()大多数使用在需要使用STL提供的算法操作string时,比如:采用reverse逆置string
其他时候基本用[ ]。
3.rbegin和rend
和begin和end类似,不过rbegin和rend返回的是反向迭代器。
reverse_iterator
rbegin()指向的最后一个字符串的反向迭代器(也就是反向迭代开头的位置的反向迭代器)
rend()是获取第一个字符之前的理论元素的反向迭代器(也就是反向最后一个字符的下一个位置的反向迭代器)
4.范围for
对于范围for,其实它的底层就是用迭代器进行迭代,auto所对应的类型其实就是迭代器类型。
for(auto e : str){ cout << e ;}cout << endl;//这里的e其实它的类型就是一个迭代器类型//auto e ———— string :: iterator e;
5.operator=
string& operator= (const string& str); |
string& operator= (const char* s); |
string& operator= (char c); |
赋值重载操作符,capacity会变大但不会变小,size会随着赋值改变
6.对于string对象的增删查改等操作
画表格太累了。。。直接从cplusplus.com上面截图了 ^ ^
1.operator +=
通过在当前字符串末尾增加字符串来扩大string,其返回值是被增加后的string的引用
加另一个str对象 | string& operator+= (const string& str); |
---|---|
加一个字符串 | string& operator+= (const char* s); |
加一个字符 | string& operator+= (char c); |
2.append 追加
效果和operator += 相同,都是通过在当前字符串末尾增加字符串来扩大string,其返回值是被增加后的string的引用
增加一个str的拷贝 | string& append (const string& str); |
增加str的一个子字符串的拷贝:从subpos位置开始依次sublen个(如果sublen过大就一直加到str的末尾位置) | string& append (const string& str, size_t subpos, size_t sublen); |
增加s指向的字符串 | string& append (const char* s); |
增加s指向的字符串的前n个字符 | string& append (const char* s, size_t n); |
在原字符串后面填充n个字符c | string& append (size_t n, char c); |
在原字符串后面增加另一个字符串的[first,last)范围的子字符串。(first和last是自己定的并不一定是从头开始到结束) | template |
以相同的顺序增加类对象il中每个字符的副本 | string& append (initializer_list |
例:
#include#include int main (){ string str; string str2="Writing "; string str3="print 10 and then 5 more"; str.append(str2); // "Writing " str.append(str3,6,3); // "10 " str.append("dots are cool",5); // "dots " str.append("here: "); // "here: " str.append(10u,'.'); // ".........." //这里就是通过改变迭代器的位置来控制了加的字符串范围 str.append(str3.begin()+8,str3.end()); // " and then 5 more" str.append (5,0x2E); // "....." cout << str << 'n'; return 0;}
3.push_back 和pop_back
push_back :尾插一个字符,size和length +1
void push_back (char c);
pop_back :尾删一个字符,size和length -1
void pop_back();
需要注意的是:push_back和pop_back只能尾插和尾删一个字符 而不能是字符串
4.assign
替换:用新的内容替换原字符串
用另一个str替换掉原来的字符串(注意如果str比原字符串短,那size会减小) | string& assign (const string& str); |
用另一个字符串的子串(subpos位置之后的sublen个元素)替换掉原字符串 | string& assign (const string& str, size_t subpos, size_t sublen); |
用一个字符串替换掉原字符串 | string& assign (const char* s); |
用字符串s的从起始位置开始n个元素组成的子字符串替换掉原来的字符串 | string& assign (const char* s, size_t n); |
用n个c字符替换掉原来的字符串 | string& assign (size_t n, char c); |
以相同的顺序用范围[first,last)内字符序列替换原字符串 | template |
按照相同的顺序复制il中的每个字符。 | string& assign (initializer_list |
获取括号里面的内容 | string& assign (string&& str) noexcept; |
int main(){ string str; string base = "The quick brown fox jumps over a lazy dog."; str.assign(base); cout << str << 'n'; str.assign(base, 10, 9); cout << str << 'n'; // "brown fox" str.assign("pangrams are cool", 7); cout << str << 'n'; // "pangram" str.assign("c-string"); cout << str << 'n'; // "c-string" str.assign(10, '*'); cout << str << 'n'; // "**********" str.assign(10, 0x2D); cout << str << 'n'; // "----------" str.assign(base.begin() + 16, base.end() - 12); cout << str << 'n'; // "fox jumps over" return 0;}
注意end()-1才是“.”哦。
5.insert
插入
在原字符串第pos位置后面插入str的拷贝 | string& insert (size_t pos, const string& str); |
---|---|
在原字符串的第pos位置后面插入str的子串的拷贝,子串为str的subpos向后数sublen个字符所组成的字符串 | string& insert (size_t pos, const string& str, size_t subpos, size_t sublen); |
在原字符串第pos位置后面插入一个字符串的拷贝 | string& insert (size_t pos, const char* s); |
在原字符串的第pos位置后面插入一个字符串的前n个字符所组成的字符串的拷贝 | string& insert (size_t pos, const char* s, size_t n); |
在原字符串的第pos位置后面插入n个c字符的拷贝 注意:这里迭代器返回的是插入的c的迭代器的拷贝 | string& insert (size_t pos, size_t n, char c);iterator insert (const_iterator p, size_t n, char c); |
插入字符c | iterator insert (const_iterator p, char c); |
在迭代器p后面插入子序列的拷贝[first , end) | template |
按照相同的顺序插入il中每个字符的副本。 | string& insert (const_iterator p, initializer_list |
int main(){ string str = "to be question"; string str2 = "the "; string str3 = "or not to be"; string::iterator it; // used in the same order as described above: str.insert(6, str2); // to be (the )question str.insert(6, str3, 3, 4); // to be (not )the question str.insert(10, "that is cool", 8); // to be not (that is )the question str.insert(10, "to be "); // to be not (to be )that is the question str.insert(15, 1, ':'); // to be not to be(:) that is the question it = str.insert(str.begin() + 5, ',');// to be(,) not to be: that is the question cout << *it << endl; // , str.insert(str.end(), 3, '.'); // to be, not to be: that is the question(...) str.insert(it+2, str3.begin(), str3.begin() + 3); // to be, (or )not to be: that is the question... std::cout << str << 'n'; return 0;}
6.erase
删除string中的一部分,并使szie和length随之减小(capacity不变)
把字符串中从第pos下标位置以及向后len个字符删除掉 注意: 1.如果len给的过大超过了size,那么会删到末尾结束 2.默认的erase会吧string对象内部的元素全部删除,从开头删到结束 | string& erase (size_t pos = 0, size_t len = npos); |
---|---|
删除迭代器p所指向的元素 | iterator erase (const_iterator p); |
删除迭代器[first , last)的元素 注意:first元素会被删除而last不会被删除 | iterator erase (const_iterator first, const_iterator last); |
注意:
1.pos是下标,是从0开始的
2.如果pos比size(length)大,那么会抛异常
3.最上面的返回*this ,另外两个返回的是迭代器(指向第一个被删除的位置目前所取代的字符的位置),如果全部被删光了就指向end()
int main(){ string str2("The bao is a joker or a handsome boy"); cout << str2 << endl; string::iterator it = str2.erase(str2.begin() + 13);//返回的是迭代器iterator it指向j原来所处的位置 cout << str2 << endl; str2.erase(it, it + 10); cout << str2 << endl; return 0;}
7.replace
将字符串中从字符pos开始并跨越len个字符的部分(或[i1,i2)之间范围内的部分)替换为新内容:
将字符串中从pos开始后面len个元素替换为str,其余不变 | string& replace(size_t pos, size_t len, const string& str);string& replace(const_iterator i1, const_iterator i2, const string&str); |
---|---|
将字符串中从pos开始后面len个元素替换为str对应的字符串中第subpos开始后面sublen个元素 | string& replace (size_t pos, size_t len, const string& str, size_t subpos, size_t sublen); |
将字符串中从pos开始后面len个元素替换为字符串s | string& replace (size_t pos,size_t len,const char* s);string& replace (const_iterator i1, const_iterator i2, const char* s); |
将字符串中从pos开始后面len个元素替换为字符串s的前n个元素 | string& replace (size_t pos, size_t len,const char* s, size_t n);string& replace (const_iterator i1, const_iterator i2, const char* s, size_t n); |
用连续的n个字符c填充替换pos开始后面len个元素 | string& replace (size_t pos,size_t len,size_t n, char c);string& replace (const_iterator i1, const_iterator i2, size_t n, char c); |
以相同的顺序复制范围 [first,last)中的字符序列替换[i1,i2)中的内容。 | template |
按照相同的顺序复制il中的每个字符替换[i1,i2)中的内容 | string& replace (const_iterator i1, const_iterator i2, initializer_list |
int main(){ string base = "this is a test string."; string str2 = "n example"; string str3 = "sample phrase"; string str4 = "useful."; // Using positions: 0123456789*123456789*12345 string str = base; // "this is a test string." str.replace(9, 5, str2); // "this is an example string." (1) str.replace(19, 6, str3, 7, 6); // "this is an example phrase." (2) str.replace(8, 10, "just a"); // "this is just a phrase." (3) str.replace(8, 6, "a shorty", 7); // "this is a short phrase." (4) str.replace(22, 1, 3, '!'); // "this is a short phrase!!!" (5) // Using iterators: 0123456789*123456789* str.replace(str.begin(), str.end() - 3, str3); // "sample phrase!!!" (1) str.replace(str.begin(), str.begin() + 6, "replace"); // "replace phrase!!!" (3) str.replace(str.begin() + 8, str.begin() + 14, "is coolness", 7); // "replace is cool!!!" (4) str.replace(str.begin() + 12, str.end() - 4, 4, 'o'); // "replace is cooool!!!" (5) str.replace(str.begin() + 11, str.end(), str4.begin(), str4.end());// "replace is useful." (6) cout << str << 'n'; return 0;}
8.swap
把原字符串和str交换
void swap (string& str);
9.pop_back
把最后一个字符给erase掉,length(size)-1.
5.string类对象的修改操作
c_str ( 重点 ) | 返回C格式字符串 |
find + npos ( 重点) | 从字符串 pos 位置开始往后找字符 c ,返回该字符在字符串中的位置 |
rfind | 从字符串 pos 位置开始往前找字符 c ,返回该字符在字符串中的位置 |
substr | 在 str 中从 pos 位置开始,截取 n 个字符,然后将其返回 |
1.c_str
返回指向一个字符串的指针,该字符串以'0'结尾
2.find
在字符串中搜索由其参数指定的序列的第一个匹配项。
当指定pos时,搜索仅包括原字符串位置pos处或之后的字符,忽略任何可能出现的位置pos之前的字符。
注意:与成员find_first_of不同,无论何时搜索多个字符,仅匹配其中一个字符是不够的,但必须匹配整个序列
查找和str序列的第一个匹配项的下标 | size_t find (const string& str, size_t pos = 0) const; |
---|---|
查找和字符串s的第一个匹配项的下标 | size_t find (const char* s, size_t pos = 0) const; |
查找和字符串s的前n个元素组成的序的第一个匹配项的下标 | size_t find (const char* s, size_t pos, size_t n) const; |
查找字符s的第一个匹配项的下标位置 | size_t find (char c, size_t pos = 0) const; |
3.refind
从下标pos位置往前找,返回第一个匹配项(也就是字符串中从前往后数最后一个匹配项)的下标
从pos下标位置开始往前找,返回第一个匹配项的下标 | size_t rfind (const string& str, size_t pos = npos) const; |
---|---|
从pos下标位置开始往前找,返回第一个匹配项的下标 | size_t rfind (const char* s, size_t pos = npos) const; |
从pos下标位置开始往前找,返回第一个匹配项的下标(和s字符串的前n个字符组成的字符串匹配) | size_t rfind (const char* s, size_t pos, size_t n) const; |
从pos下标位置开始往前找,返回第一个和字符c匹配的匹配项的下标 | size_t rfind (char c, size_t pos = npos) const; |
4.substr
string substr (size_t pos = 0, size_t len = npos) const;
返回一个新构造的对象,对原字符串从pos下标位置开始往后len个元素组成的字符串进行拷贝构造string对象。
注意:如果 pos 大于字符串长度,则会引发out_of_range异常。
int main (){ string str="We think in generalities, but we live in details."; // (quoting Alfred N. Whitehead) string str2 = str.substr (3,5); // str2 "think" size_t pos = str.find("live"); // position of "live" in str string str3 = str.substr (pos); // str3 "live in details" cout << str2 << ' ' << str3 << 'n'; return 0;}
注意:
1.在string尾部追加字符时,push_back、append、+=三种的实现方式差不多,一般情况下用+=操作的比较多,因为+=不仅可以连接单个字符还可以连接字符串。
2.对stirng操作时,如果能够大概预估到放多少个字符,建议先用reserve吧空间开辟好。
6.非成员函数重载
operator+ | 尽量少用,因为传值返回,导致深拷贝效率低 |
operator>> (重点) | 输入运算符重载 |
operator<< (重点) | 输出运算符重载 |
getline (重点) | 获取一行字符串 |
relational operators (重点) | 大小比较 |
1.operator+
返回一个新构造的字符串对象,其值为lhs中的字符与rhs中的字符串的串联。
(在lhs后面追加rhs)
在lhs后面追加rhs,返回追加之后的string对象的拷贝 | string operator+ (const string& lhs, const string& rhs); |
---|---|
在string对象后面追加字符串和在字符串后面追加string对象,返回追加之后的拷贝 | string operator+ (const string& lhs, const char* rhs);string operator+ (const char* lhs, const string& rhs); |
在string对象后面追加字符和在字符后面追加string对象,返回追加之后的拷贝 | string operator+ (const string& lhs, char rhs);string operator+ (char lhs, const string& rhs); |
2.operator>>和operator<<
>>:从流中提取字符串
istream& operator>> (istream& is, string& str);
<<:将字符串插入流
ostream& operator<< (ostream& os, const string& str);
所返回的istream和ostream类型的引用都是为了连续流提取和连续流插入
int main(){ string name; cout << "Please, enter your name: "; cin >> name; cout << "Hello, " << name << "!n"; return 0;}
3.getline
将一行数据从流中提取出来转换为string对象
从 is 中提取字符并将其存储到 str 中,直到找到分隔字符 delim | istream& getline (istream& is, string& str, char delim); |
---|---|
从 is 中提取字符并将其存储到 str 中,直到找到分隔字符——换行符“n”。 | istream& getline (istream& is, string& str); |
如果找到分隔符,则将其提取并丢弃(即不存储它,下一个输入操作将在它之后开始)。
请注意,调用之前的任何内容都将替换为新提取的序列。(即str会改变)
每个提取的字符都追加到字符串中,就像调用其成员push_back一样。
int main(){ string name; cout << "Please, enter your full name: "; getline(cin, name); cout << "Hello, " << name << "!n"; return 0;}
4.relational operator(string)
判断string类对象之间、string类对象和字符串之间是否相等 | bool operator== (const string& lhs, const string& rhs);bool operator== (const char* lhs, const string& rhs);bool operator== (const string& lhs, const char* rhs); |
---|---|
判断string类对象之间、string类对象和字符串之间是否不相等 | bool operator!= (const string& lhs, const string& rhs);bool operator!= (const char* lhs, const string& rhs);bool operator!= (const string& lhs, const char* rhs); |
判断string类对象之间、string类对象和字符串之间是否小于(从第一个字符开始向后比较,谁小谁就小) | bool operator< (const string& lhs, const string& rhs);bool operator< (const char* lhs, const string& rhs);bool operator< (const string& lhs, const char* rhs); |
判断string类对象之间、string类对象和字符串之间是否小于等于(从第一个字符开始向后比较,谁小谁就小) | bool operator<= (const string& lhs, const string& rhs);bool operator<= (const char* lhs, const string& rhs);bool operator<= (const string& lhs, const char* rhs); |
和小于的重载类似 | bool operator> (const string& lhs, const string& rhs);bool operator> (const char* lhs, const string& rhs);bool operator> (const string& lhs, const char* rhs); |
和小于等于的重载类似 | bool operator>= (const string& lhs, const string& rhs);bool operator>= (const char* lhs, const string& rhs);bool operator>= (const string& lhs, const char* rhs); |