3.5 string类对象的修改器(Modifiers)
函数名称 | 功能说明 |
operator+= | 用于字符串的连接 |
append | 在字符串末尾添加字符或字符序列 |
push_back | 在字符串末尾添加一个字符 |
assign | 将新的内容赋值给字符串对象,从而修改字符串的内容 |
insert | 在指定位置 pos 处插入字符或字符序列 |
erase | 删除指定位置的字符或字符范围 |
replace | 替换指定位置或字符范围的字符 |
swap | 调用该函数的字符串对象与参数表示的另一个字符串对象的内容进行交换 |
pop_back | 删除字符串中的最后一个字符 |
1.operator+=
+= 运算符是字符串的连接操作符,也称为字符串的拼接运算符。使用 += 运算符,您可以将一个字符串连接到另一个字符串的末尾,从而实现字符串的拼接。
+= 运算符的原型如下:
basic_string& operator+=(const basic_string& str); basic_string& operator+=(const charT* s); basic_string& operator+=(charT ch);
+= 运算符有三个重载版本,分别用于将另一个字符串、C 风格字符串(以 null 结尾的字符数组)或单个字符连接到当前字符串的末尾。
示例:
std::string str = "Hello"; str += " World"; // 将字符串 " World" 连接到 str 的末尾,现在 str 变为 "Hello World" str += '!'; // 将字符 '!' 连接到 str 的末尾,现在 str 变为 "Hello World!"
在上述示例中,我们通过使用 += 运算符将字符串 " World" 和字符 ‘!’ 连接到字符串 str 的末尾,实现了字符串的拼接。
需要注意的是,+= 运算符会直接修改调用它的字符串对象,将指定的内容连接到字符串的末尾。如果你希望连接两个字符串而不修改原始字符串,可以使用 + 运算符来创建一个新的字符串,而不会修改原有的字符串对象。例如:
std::string str1 = "Hello"; std::string str2 = " World"; std::string combined = str1 + str2; // 创建一个新的字符串,不修改原有字符串
使用 += 运算符或 + 运算符,取决于你希望修改原有字符串还是创建新的字符串,或者根据具体的需求来选择适合的方法。
2.append
append() 函数用于在字符串的末尾添加字符或字符序列,从而实现字符串的拼接。
append() 函数有多个重载形式,提供了不同的方式来添加内容到字符串的末尾。以下是 std::string 类中 append() 函数的几种重载形式及其介绍和使用方法:
basic_string& append(const charT* s);
这个重载函数将一个 C 风格字符串(以 null 结尾的字符数组)添加到字符串的末尾。
std::string str = "Hello"; str.append(" World"); // 在末尾添加字符串 " World",现在 str 为 "Hello World"
basic_string& append(const charT* s, size_type n);
这个重载函数将一个指定长度的字符数组添加到字符串的末尾。
std::string str = "Hello"; str.append(" World", 5); // 在末尾添加字符数组 " Worl"(前5个字符),现在 str 为 "Hello Worl"
basic_string& append(const basic_string& str);
这个重载函数将另一个 std::string 对象的内容添加到当前字符串的末尾。
std::string str1 = "Hello"; std::string str2 = " World"; str1.append(str2); // 将 str2 的内容添加到 str1 的末尾,现在 str1 为 "Hello World"
basic_string& append(const basic_string& str, size_type pos, size_type n);
这个重载函数将另一个 std::string 对象从指定位置 pos 处开始的 n 个字符添加到当前字符串的末尾。
std::string str1 = "Hello"; std::string str2 = "World"; str1.append(str2, 1, 3); // 将 str2 从位置1(包含)开始的3个字符 "orl" 添加到 str1 的末尾,现在 str1 为 "Helloorl"
basic_string& append(size_type n, charT ch);
这个重载函数将重复 n 次的字符 ch 添加到字符串的末尾。
std::string str = "Hello"; str.append(3, '!'); // 在末尾添加3个字符 '!',现在 str 为 "Hello!!!"
这些 append() 函数提供了多种方式来将内容添加到字符串的末尾,从而实现字符串的拼接。
3.push_back
void push_back(charT ch);
使用 push_back() 函数可以将一个字符 ch 添加到字符串的末尾。
示例:
std::string str = "Hello"; str.push_back('!'); // 在末尾添加字符 '!',现在 str 变为 "Hello!"
在上述示例中,我们通过使用 push_back() 函数在字符串 str 的末尾添加了字符 ‘!’,从而实现了在字符串中添加一个字符的操作。
需要注意的是,push_back() 函数会直接修改调用它的字符串对象,在字符串的末尾添加指定的字符。在使用 push_back() 之前,应该确保字符串的长度仍然在合理的范围内,避免发生字符串的溢出。在实际使用中,务必注意处理字符串长度和内存的限制。另外,C++11 之后的版本还引入了字符串拼接操作符 +=,可以使用 += 运算符来在字符串的末尾添加字符,更加简洁方便。
4.assign
assign() 函数用于将新的内容赋值给字符串对象,从而修改字符串的内容。
assign() 函数有多个重载形式,提供了不同的方式来赋值新的内容给字符串。以下是 std::string 类中 assign() 函数的几种重载形式及其介绍和使用方法:
basic_string& assign(const charT* s);
这个重载函数将一个 C 风格字符串(以 null 结尾的字符数组)赋值给字符串对象。
std::string str; str.assign("Hello"); // 将 C 风格字符串 "Hello" 赋值给字符串对象 str
basic_string& assign(const charT* s, size_type n);
这个重载函数将一个指定长度的字符数组赋值给字符串对象。
std::string str; str.assign("Hello", 3); // 将字符数组 "Hel"(前三个字符)赋值给字符串对象 str
basic_string& assign(const basic_string& str);
这个重载函数将另一个 std::string 对象的内容赋值给当前字符串对象。
std::string str1 = "Hello"; std::string str2; str2.assign(str1); // 将 str1 的内容赋值给 str2
basic_string& assign(const basic_string& str, size_type pos, size_type n);
这个重载函数将另一个 std::string 对象从指定位置 pos 处开始的 n 个字符赋值给当前字符串对象。
std::string str1 = "Hello"; std::string str2; str2.assign(str1, 1, 3); // 将 str1 从位置1(包含)开始的3个字符 "ell" 赋值给 str2
basic_string& assign(size_type n, charT ch);
这个重载函数将重复 n 次的字符 ch 赋值给字符串对象。
std::string str; str.assign(5, 'x'); // 将字符 'x' 重复5次赋值给字符串对象 str,结果为 "xxxxx"
这些 assign() 函数提供了多种方式来将新的内容赋值给字符串对象,从而修改字符串的内容。
5.insert
insert() 函数用于在指定位置插入字符或字符序列,从而改变字符串的内容。
insert() 函数有多个重载形式,提供了不同的方式来在字符串中插入字符或字符序列。以下是 std::string 类中 insert() 函数的几种重载形式及其介绍和使用方法:
basic_string& insert(size_type pos, const charT* s);
这个重载函数在字符串中的指定位置 pos 处插入一个 C 风格字符串(以 null 结尾的字符数组)。
std::string str = "Hello"; str.insert(2, "xx"); // 在位置2处插入字符串 "xx",现在 str 变为 "Hexxllo"
basic_string& insert(size_type pos, const charT* s, size_type n);
这个重载函数在字符串中的指定位置 pos 处插入一个指定长度的字符数组。
std::string str = "Hello"; str.insert(3, "xx", 1); // 在位置3处插入字符数组 "x"(前1个字符),现在 str 变为 "Helxlo"
basic_string& insert(size_type pos, const basic_string& str);
这个重载函数在字符串中的指定位置 pos 处插入另一个 std::string 对象的内容。
std::string str1 = "Hello"; std::string str2 = " World"; str1.insert(5, str2); // 在位置5处插入 str2 的内容,现在 str1 变为 "Hello World"
basic_string& insert(size_type pos, const basic_string& str, size_type subpos, size_type sublen);
这个重载函数在字符串中的指定位置 pos 处插入另一个 std::string 对象的子字符串,从 str 的 subpos 处开始,长度为 sublen。
std::string str1 = "Hello"; std::string str2 = "World"; str1.insert(5, str2, 0, 3); // 在位置5处插入 str2 的子字符串 "Wor",现在 str1 变为 "HelloWor"
basic_string& insert(size_type pos, size_type n, charT ch);
这个重载函数在字符串中的指定位置 pos 处插入重复 n 次的字符 ch。
std::string str = "Hello"; str.insert(2, 3, 'x'); // 在位置2处插入3个字符 'x',现在 str 变为 "Hexxxello"
这些 insert() 函数提供了多种方式来在字符串中插入字符或字符序列,从而实现字符串内容的修改。
6.erase
erase() 函数用于从字符串中删除指定位置的字符或字符序列,从而修改字符串的内容。
erase() 函数有多个重载形式,提供了不同的方式来删除字符串中的字符或字符序列。以下是 std::string 类中 erase() 函数的几种重载形式及其介绍和使用方法:
basic_string& erase(size_type pos = 0, size_type n = npos);
这个重载函数删除从指定位置 pos 开始的 n 个字符(默认情况下,删除从 pos 开始的所有字符)。
std::string str = "Hello World"; str.erase(5); // 删除从位置5(包含)开始的所有字符,现在 str 变为 "Hello" str.erase(0, 3); // 删除从位置0(包含)开始的3个字符,现在 str 变为 "lo"
iterator erase(const_iterator position);
这个重载函数删除指定位置 position 处的字符,并返回一个指向删除后的下一个字符的迭代器。
std::string str = "Hello"; auto it = str.erase(str.begin() + 1); // 删除位置1处的字符 'e',现在 str 变为 "Hllo",it 指向 'l'
iterator erase(const_iterator first, const_iterator last);
这个重载函数删除从 first 到 last-1之间的字符,并返回一个指向删除后的下一个字符的迭代器。
std::string str = "Hello World"; auto first = str.begin() + 6; // 指向字符 'W' auto last = str.begin() + 11; // 指向字符 '\0' auto it = str.erase(first, last); // 删除字符 'W' 到 '\0'(不包括\0),现在 str 变为 "Hello ",it 指向 '\0'
这些 erase() 函数提供了多种方式来删除字符串中的字符或字符序列,从而实现字符串内容的修改。
7.replace
replace()函数用于将字符串中的一部分内容替换为新的子串。
replace() 函数有多个重载形式,提供了不同的方式来替换字符串中的一部分内容。以下是 std::string 类中 replace() 函数的几种重载形式及其描述和使用方法:
basic_string& replace(size_type pos, size_type count, const charT* s);
这个重载函数从字符串的位置 pos 开始,用指定的 C 风格字符串(以 null 结尾的字符数组)替换 count 个字符。
std::string str = "Hello, World!"; str.replace(7, 5, "Universe"); // 从位置 7 开始,用 "Universe" 替换 5 个字符,现在 str 变为 "Hello, Universe!"
basic_string& replace(size_type pos, size_type count, const charT* s, size_type n);
这个重载函数从字符串的位置 pos 开始,用指定长度的字符数组中的前 n 个字符替换 count 个字符。
std::string str = "Hello, World!"; str.replace(7, 5, "Earth", 3); // 从位置 7 开始,用 "Ear"("Earth" 的前 3 个字符)替换 5 个字符,现在 str 变为 "Hello, Ear, World!"
basic_string& replace(size_type pos, size_type count, const basic_string& str);
这个重载函数从字符串的位置 pos 开始,用另一个 std::string 对象的内容替换 count 个字符。
std::string str1 = "Hello, World!"; std::string str2 = "Universe"; str1.replace(7, 5, str2); // 从位置 7 开始,用 str2 的内容 "Universe" 替换 5 个字符,现在 str1 变为 "Hello, Universe!"
basic_string& replace(size_type pos, size_type count, const basic_string& str, size_type pos2, size_type count2);
这个重载函数从字符串的位置 pos 开始,用另一个 std::string 对象 str 的从 pos2 处开始的 count2 个字符替换 count 个字符。
std::string str1 = "Hello, World!"; std::string str2 = "Universe"; str1.replace(7, 5, str2, 0, 3); // 从位置 7 开始,用 str2 的子串 "Uni"(从位置 0 开始的 3 个字符)替换 5 个字符,现在 str1 变为 "Hello, Uni, World!"
basic_string& replace(iterator first, iterator last, const charT* s);
这个重载函数用指定的 C 风格字符串(以 null 结尾的字符数组)替换从 first 到 last-1 之间的字符。
std::string str = "Hello, World!"; auto first = str.begin() + 7; // 指向字符 'W' auto last = str.begin() + 12; // 指向字符 '!' str.replace(first, last, "Universe"); // 用 "Universe" 替换 'W' 到 '!'(不包括!),现在 str 变为 "Hello, Universe!"
basic_string& replace(iterator first, iterator last, const basic_string& str);
这个重载函数用另一个 std::string 对象 str 的内容替换从 first 到 last-1 之间的字符。
std::string str1 = "Hello, World!"; std::string str2 = "Universe"; auto first = str1.begin() + 7; // 指向字符 'W' auto last = str1.begin() + 12; // 指向字符 '!' str1.replace(first, last, str2); // 用 str2 的内容 "Universe" 替换 'W' 到 '!'(不包含 '!'),现在 str1 变为 "Hello, Universe!"
这些 replace() 函数提供了多种方式来替换字符串中的一部分内容,从而实现字符串内容的修改。
8.swap
swap() 函数没有参数,它将调用它的字符串对象与另一个字符串对象进行内容交换。
std::string str1 = "Hello"; std::string str2 = "World"; str1.swap(str2); // 将 str1 和 str2 的内容交换,现在 str1 变为 "World",str2 变为 "Hello"
在上述示例中,通过调用 str1.swap(str2),我们将 str1 和 str2 的内容进行了交换,str1 变为 “World”,而 str2 变为 “Hello”。
这个函数可以在交换两个字符串的内容时非常有用,而不需要对字符逐个交换或使用临时变量来完成交换。由于 swap() 是一个成员函数,所以可以通过调用它来直接对字符串对象进行交换操作,使得代码更简洁和高效。
9.pop_back
pop_back() 函数没有参数,它只需调用它的字符串对象,就会将最后一个字符从字符串中删除。
std::string str = "Hello"; str.pop_back(); // 删除最后一个字符,现在 str 变为 "Hell"
在上述示例中,通过调用 str.pop_back(),我们将字符串 str 的最后一个字符 ‘o’ 删除,从而得到新的字符串 “Hell”。
需要注意的是,使用 pop_back() 之前,应该确保字符串的长度不为零,否则会引发未定义的行为。在调用 pop_back() 之前,通常需要检查字符串是否为空。
3.6 string类对象的操作函数(operations)
1.c_str():
const char* c_str() const;
这个函数返回一个指向以 null 结尾的字符数组(C 字符串)的指针,表示当前字符串的内容。
示例:
std::string str = "Hello"; const char* cstr = str.c_str(); // cstr 指向 "Hello" 的 C 字符串形式
2.data():
const char* data() const;
这个函数返回一个指向字符数组的指针,表示当前字符串的内容。与 c_str() 类似,但 data() 不一定以 null 结尾。
示例:
std::string str = "Hello"; const char* strData = str.data(); // strData 指向 "Hello" 的字符数组形式
3.get_allocator():
allocator_type get_allocator() const noexcept;
这个函数返回当前字符串使用的分配器的副本。
示例:
std::string str = "Hello"; std::allocator<char> alloc = str.get_allocator(); // 获取 str 的分配器副本
4.copy():
size_type copy(charT* dest, size_type count, size_type pos = 0) const;
这个函数从当前字符串中复制 count 个字符到指定位置 pos 开始的字符数组 dest。
示例:
std::string str = "Hello"; char buffer[6]; str.copy(buffer, 5); // 将 str 的前 5 个字符复制到 buffer 中,buffer 现在为 "Hello\0"(带有 null 终止符)
5.find()、rfind()、find_first_of()、find_last_of()、find_first_not_of()、find_last_not_of():
这些函数用于在当前字符串中搜索指定的字符或子字符串,并返回找到的第一个匹配位置或位置偏移。
示例:
std::string str = "Hello, World!"; size_t pos = str.find("World"); // 在 str 中找到子字符串 "World",返回位置 7 size_t lastPos = str.rfind("l"); // 从字符串末尾开始找到字符 'l',返回位置 9 size_t foundPos = str.find_first_of(",!"); // 在 str 中找到第一个出现的 ',' 或 '!',返回位置 5
6. substr():
basic_string substr(size_type pos = 0, size_type count = npos) const;
这个函数返回一个新的字符串,包含从位置 pos 开始的 count 个字符的副本。
示例:
void DealUrl(const string& url) { size_t pos1 = url.find("://"); if (pos1 == string::npos) { cout << "非法url" << endl; return; } string protocol = url.substr(0, pos1); cout << protocol << endl; size_t pos2 = url.find('/', pos1 + 3); if (pos2 == string::npos) { cout << "非法url" << endl; return; } string domain = url.substr(pos1+3, pos2-pos1-3); cout << domain << endl; string uri = url.substr(pos2 + 1); cout << uri << endl << endl; } int main() { string url1 = "https://cplusplus.com/reference/string/string/"; string url2 = "https://image.baidu.com/search/detail?ct=503316480&z=0&ipn=d&word=ascall&step_word=&hs=0&pn=0&spn=0&di=7108135681917976577&pi=0&rn=1&tn=baiduimagedetail&is=0%2C0&istype=0&ie=utf-8&oe=utf-8&in=&cl=2&lm=-1&st=undefined&cs=2613959014%2C543572025&os=2740573600%2C1059518451&simid=2613959014%2C543572025&adpicid=0&lpn=0&ln=179&fr=&fmq=1660115697093_R&fm=&ic=undefined&s=undefined&hd=undefined&latest=undefined©right=undefined&se=&sme=&tab=0&width=undefined&height=undefined&face=undefined&ist=&jit=&cg=&bdtype=0&oriquery=&objurl=https%3A%2F%2Fgimg2.baidu.com%2Fimage_search%2Fsrc%3Dhttp%3A%2F%2Fimg.php.cn%2Fupload%2Fimage%2F147%2F157%2F796%2F1593765739620093.png%26refer%3Dhttp%3A%2F%2Fimg.php.cn%26app%3D2002%26size%3Df9999%2C10000%26q%3Da80%26n%3D0%26g%3D0n%26fmt%3Dauto%3Fsec%3D1662707704%26t%3Da68cb238bbb3f99d0554098c785d526e&fromurl=ippr_z2C%24qAzdH3FAzdH3Fooo_z%26e3Brir_z%26e3BvgAzdH3FuwqAzdH3F9c9amd_z%26e3Bip4s&gsm=1&rpstart=0&rpnum=0&islist=&querylist=&nojc=undefined&dyTabStr=MCwzLDIsNCw2LDEsNSw3LDgsOQ%3D%3D"; string url3 = "ftp://ftp.cs.umd.edu/pub/skipLists/skiplists.pdf"; DealUrl(url1); DealUrl(url2); DealUrl(url3); return 0; }
7.compare():
int compare(const basic_string& str) const noexcept;
这个函数用于比较当前字符串与另一个 std::string 对象 str 的大小关系。
示例:
std::string str1 = "Hello"; std::string str2 = "World"; int result = str1.compare(str2); // 返回一个整数,表示 str1 和 str2 的大小关系(类似于字符串比较的结果)
这些成员函数提供了丰富的功能,用于处理字符串的查找、比较、复制、截取等操作。
3.7 string类对象的非成员函数和npos
1.operator+(重载运算符+):
template <class CharT, class Traits, class Allocator> basic_string<CharT, Traits, Allocator> operator+( const basic_string<CharT, Traits, Allocator>& lhs, const basic_string<CharT, Traits, Allocator>& rhs);
这个函数模板用于将两个 std::string 对象进行字符串连接,返回一个新的 std::string 对象,包含两个原始字符串的内容。
示例:
std::string str1 = "Hello"; std::string str2 = " World"; std::string result = str1 + str2; // 返回 "Hello World"
2.关系运算符(Relational operators):
template <class CharT, class Traits, class Allocator> bool operator==( const basic_string<CharT, Traits, Allocator>& lhs, const basic_string<CharT, Traits, Allocator>& rhs); template <class CharT, class Traits, class Allocator> bool operator!=( const basic_string<CharT, Traits, Allocator>& lhs, const basic_string<CharT, Traits, Allocator>& rhs); template <class CharT, class Traits, class Allocator> bool operator<( const basic_string<CharT, Traits, Allocator>& lhs, const basic_string<CharT, Traits, Allocator>& rhs); template <class CharT, class Traits, class Allocator> bool operator<=( const basic_string<CharT, Traits, Allocator>& lhs, const basic_string<CharT, Traits, Allocator>& rhs); template <class CharT, class Traits, class Allocator> bool operator>( const basic_string<CharT, Traits, Allocator>& lhs, const basic_string<CharT, Traits, Allocator>& rhs); template <class CharT, class Traits, class Allocator> bool operator>=( const basic_string<CharT, Traits, Allocator>& lhs, const basic_string<CharT, Traits, Allocator>& rhs);
这些函数模板用于对 std::string 对象进行大小比较。可以通过这些运算符对两个字符串进行逐个字符的比较,从而确定它们的大小关系。
示例:
std::string str1 = "Hello"; std::string str2 = "World"; bool isEqual = (str1 == str2); // 返回 false,因为 str1 不等于 str2 bool isGreater = (str1 > str2); // 返回 true,因为 str1 大于 str2
3.swap():
template <class CharT, class Traits, class Allocator> void swap( basic_string<CharT, Traits, Allocator>& lhs, basic_string<CharT, Traits, Allocator>& rhs);
这个函数模板用于交换两个 std::string 对象的内容,实现两个字符串的快速交换。
示例:
std::string str1 = "Hello"; std::string str2 = "World"; swap(str1, str2); // 将 str1 和 str2 的内容交换,现在 str1 变为 "World",str2 变为 "Hello"
4.operator>> 和 operator<<(重载运算符>>和<<):
template <class CharT, class Traits, class Allocator> std::basic_istream<CharT, Traits>& operator>>( std::basic_istream<CharT, Traits>& is, basic_string<CharT, Traits, Allocator>& str); template <class CharT, class Traits, class Allocator> std::basic_ostream<CharT, Traits>& operator<<( std::basic_ostream<CharT, Traits>& os, const basic_string<CharT, Traits, Allocator>& str);
这些函数模板用于在输入输出流中读取或输出字符串内容。operator>> 用于从输入流中提取字符串,而 operator<< 用于将字符串插入到输出流中。
示例:
std::string str; std::cout << "请输入一个字符串:"; std::cin >> str; // 从标准输入流中读取字符串 std::cout << "您输入的字符串是:" << str << std::endl; // 将字符串输出到标准输出流
5.getline():
template <class CharT, class Traits, class Allocator> std::basic_istream<CharT, Traits>& getline( std::basic_istream<CharT, Traits>& is, basic_string<CharT, Traits, Allocator>& str, CharT delim);
这个函数模板用于从输入流中读取一行内容,并将其存储到字符串 str 中,直到遇到指定的分隔符 delim。
示例:
std::string str; std::cout << "请输入一行文本:"; std::getline(std::cin, str); // 从标准输入流中读取一行文本并存储到 str 中 std::cout << "您输入的文本是:" << str << std::endl;
这些函数和操作符提供了丰富的功能,可以方便地对字符串进行连接、比较、输入输出等操作。
npos
npos 是 std::string 类中的一个静态常量成员,用于表示无效或未找到的位置。它是一个特殊的 std::string::size_type 类型的常量,通常被定义为 std::string::npos,其值在不同的编译器和实现中可能不同,但通常被设为 -1 或一个非常大的值,用于表示在字符串中未找到指定的子串或字符。
npos 主要用于字符串查找操作,比如在使用 find()、rfind()、find_first_of()、find_last_of()、find_first_not_of()、find_last_not_of() 等成员函数时,当查找失败或没有找到指定的子串或字符时,这些函数通常会返回 std::string::npos 来表示无效的位置。
示例:
std::string str = "Hello, World!"; std::string::size_type pos1 = str.find("Universe"); // 在 str 中找不到 "Universe",返回 std::string::npos std::string::size_type pos2 = str.find('X'); // 在 str 中找不到字符 'X',返回 std::string::npos std::string::size_type pos3 = str.find("World"); // 在 str 中找到 "World",返回 "World" 在 str 中的位置
在上述示例中,当在字符串 str 中找不到 “Universe” 或字符 ‘X’ 时,find() 函数会返回 std::string::npos 表示查找失败。而当找到 “World” 时,find() 函数会返回 “World” 在字符串中的位置。
注意:npos 的值是一个非常大的无符号整数,因此在比较 std::string::size_type 类型的值时,应使用无符号类型的比较方式,避免可能出现的错误。比如使用 pos != std::string::npos 来判断是否找到了指定的子串或字符。
4.vs和g++下string结构的说明
注意:下述结构是在32位平台下进行验证,32位平台下指针占4个字节。
4.1 vs下string的结构
string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义string中字符串的存储空间:
当字符串长度小于16时,使用内部固定的字符数组来存放
当字符串长度大于等于16时,从堆上开辟空间
union _Bxty { // storage for small buffer or pointer to larger one value_type _Buf[_BUF_SIZE]; pointer _Ptr; char _Alias[_BUF_SIZE]; // to permit aliasing } _Bx;
这种设计也是有一定道理的,大多数情况下字符串的长度都小于16,那string对象创建好之后,内部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高。其次,还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量,最后还有一个指针做一些其他事情。故总共占16+4+4+4=28个字节。
4.2 g++下string的结构
g++下,string是通过写时拷贝实现的,string对象总共占4个字节,内部只包含了一个指针,该指针将来指向一块堆空间,内部包含了如下字段:
空间总大小
字符串有效长度
引用计数
指向堆空间的指针,用来存储字符串。
4.3 vs和g++的string扩容机制
在 C++ 标准中,并未规定 std::string 的扩容机制,因此不同的编译器可能有不同的实现方式。但是,通常情况下,std::string 类的扩容机制都会遵循以下一般原则:
- 初始容量:当创建一个空的 std::string 对象时,编译器会为其分配一些初始的内存空间。这个初始容量可以是一个较小的值,例如 15 或 31,具体取决于编译器的实现。
- 扩容策略:当需要向 std::string 中添加字符时,如果当前容量不足,编译器会自动触发扩容操作。扩容的方式可能是重新分配更大的内存块,并将原有的内容拷贝到新的内存中。
- 扩容大小:在扩容时,编译器通常会增加当前容量的一定倍数,以避免频繁的扩容操作。这样做可以提高字符串的插入效率,但也会导致有些内存可能浪费。
比如下面这段代码在Windows vs2022 的环境下和Linux g++环境下
#include <iostream> #include <string> using namespace std; int main() { string s; size_t sz = s.capacity(); cout << "making s grow:\n"; for (int i = 0; i < 100; ++i) { s.push_back('c'); if (sz != s.capacity()) { sz = s.capacity(); cout << "capacity changed: " << sz << endl; } } return 0; }
vs2022
g++
结语
有兴趣的小伙伴可以关注作者,如果觉得内容不错,请给个一键三连吧,蟹蟹你哟!!!
制作不易,如有不正之处敬请指出
感谢大家的来访,UU们的观看是我坚持下去的动力
在时间的催化剂下,让我们彼此都成为更优秀的人吧!!!