1.string的大小与容量
size_t size() const;
bool empty() const;
void resize (size_t n);
void resize (size_t n, char c);
void reserve (size_t n = 0);//默认实参是0,如果不传参,和shrink_to_fit的效果相同
void shrink_to_fit();
string中的reserve可以缩减内存,而vector中的reserve只能预分配内存
void reservestring()
{
string s="1234567890";
s.reserve(100);
cout<<s<<','<<s.capacity()<<endl;
s.reserve();
cout<<s<<','<<s.capacity()<<endl;
}
在调用reserve后,string的capacity变小了,效果同shrink_to_fit
其余的同vector,见博客https://blog.csdn.net/Master_Cui/article/details/107503634
2.交换两个string
void swap (string& str);
void swap (string& x, string& y);
和vector几乎相同,见博客https://blog.csdn.net/Master_Cui/article/details/107427911
3.string的迭代器失效
string和vector迭代器失效的情况类似但是并不完全一样,关于vector迭代器失效讲解见博客https://blog.csdn.net/Master_Cui/article/details/107503634
string和vector分配内存的情况几乎是一样的,但是string在分配内存时是有优化的,这一点导致string和vector迭代器失效的情况类似但是并不完全一样
在Ubuntu18.04下,string对象存在SSO(短字符串优化策略),即,当字符串的长度小于等于15时,字符串本身所占的内存被分配在栈内存上,如果字符串长度大于15,那么字符串本身所占的内存会被分配在堆内存上
SSO优化的原因:C++的std::string都是存储在heap中,导致访问std::string需要经过一次寻址过程,速度较慢。所以,很多string的字符串长度很小时,把字符串存储到栈上,从而快速分配内存,优化创建速度,并且访问栈上数据的局部性很好,速度比较快。
所以如果swap的两个字符串都是长度大于15的,那么不会产生迭代器失效,两个字符串任何一个的长度小于15,那么就会产生迭代器失效的问题
示例
void iteratorfailed2()
{
string s1="1234567890qwertyuiop";
string s2="1234567890";
string::iterator it1=s1.begin()+10;
string::iterator it2=s2.begin()+3;
cout<<*it1<<" "<<*it2<<endl;
swap(s1,s2);
cout<<s1<<endl<<s2<<endl;
cout<<*it1<<" "<<*it2<<endl;
}
可见,当swap后,it2指向的内存已经不是swap前s2所占的内存,所以没有输出正确的字符,原因就是s2的数据存储在栈内存上,交换后,原来的s2数据的栈内存被释放后又被重新分配
所以,当在Linux下做字符串的swap操作时,要注意字符串的长度是否大于15,如果小于等于15,会由迭代器失效的风险
除了swap之外,其他迭代器失效的情况和vector类似
1).string重新分配内存
void iteratorfailed()
{
string s="1234567890";
string s2="qwertyuio";
string::iterator it = s.begin();
cout<<*it<<endl;
s.insert(s.size(), s2, 0, 8);
cout<<s<<endl;
cout<<*it<<endl;
}
2).保存了插入位置之后的迭代器
这种情况对于长度小于15的字符串,插入删除位置之后的迭代器依然有效
当字符创长度大于15时,string的数据的内存在堆内存上,堆内存连续,所以迭代器失效
void iteratorfailed3()
{
string s="1234567890qwertyuiop";
string::iterator it=s.begin()+3;
cout<<*it<<endl;
s.insert(s.begin(), 'c');
cout<<s<<endl;
cout<<*it<<endl;
}
当字符串长度小于15时,此时,string的数据的内存在栈内存上,栈内存连续,所以迭代器依然有效
void iteratorfailed2()
{
string s="1234567890";
string::iterator it=s.begin()+3;
cout<<*it<<endl;
s.insert(s.begin(), 'c');
cout<<s<<endl;
cout<<*it<<endl;
}
但是,无论字符串的长度大于还是小于15,当保存了删除位置之后的迭代器,进行删除操作后解引用该迭代器,该迭代器都是有效的,不知道为啥,可能和编译器有关,也可能和系统实现有关(如果有人知道为啥,请告诉博主)
void iteratorfailed4()
{
string s="1234567890qwertyuiop";
string::iterator it=s.begin()+7;
cout<<*it<<endl;
s.erase(s.begin()+2);
cout<<s<<endl;
cout<<*it<<endl;
}
void iteratorfailed4()
{
string s="1234567890";
string::iterator it=s.begin()+7;
cout<<*it<<endl;
s.erase(s.begin()+2);
cout<<s<<endl;
cout<<*it<<endl;
}
上述两种情况,删除位置之后的迭代器都是有效的,但是,在编写程序时,不要这么做
3).解引用了insert或erase后的迭代器
void iteratorfailed5()
{
string s="1234567890qwertyuiop";
string::iterator it = s.begin()+5;
s.insert(s.begin(), *it);
cout<<*it<<endl;
}
没有输出对应的元素,因为string的迭代器失效,解决办法是利用返回值更新it
在Linux下如果string对象的长度小于15,那么insert之后,迭代器依然有效,原因仍然和SSO有关
void iteratorfailed5()
{
string s="1234567890";
string::iterator it = s.begin()+5;
s.insert(s.begin(), *it);
cout<<*it<<endl;
}
erase同理
void iteratorfailed6()
{
string s="1234567890qwertyuiop";
string::iterator it = s.begin()+5;
s.erase(*it);
cout<<*it<<endl;
}
无论string的长度是否小于15,迭代器均失效
4).在执行删除操作时,逻辑不严谨,导致解引用了尾后迭代器
void iteratorfailed7()
{
string s="123456789";
string::iterator it=s.begin();
while(it!=s.end()) {
it=s.erase(it);
++it;
cout<<*it<<endl;
}
}
解决办法见博客https://blog.csdn.net/Master_Cui/article/details/107503634
总结:
string的迭代器失效和vector类似也可以分为5种情况
1.向string对象中添加元素,导致string重新分配内存
2.在insert前,保存了insert位置之后的迭代器,在insert之后,解引用该迭代器(这种情况受SSO机制的影响),但是erase操作时,没有该问题,可能和系统实现有关
3.insert或erase之后,迭代器没有及时更新,导致迭代器失效
4.没有添加对应的逻辑判断,导致解引用了尾后迭代器
5.在Linux下,对于长度小于15的string对象,受SSO机制的影响,swap后,会导致长度小于15的string对象的迭代器失效
参考
《C++ Primer》
http://www.cplusplus.com/reference/string/string/string/
https://www.cnblogs.com/ll-10/p/9633968.html
https://blog.csdn.net/ThorKing01/article/details/97273850
https://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html
https://www.cnblogs.com/houjun/p/4909413.html
欢迎大家评论交流,作者水平有限,如有错误,欢迎指出