<string>是C++標準程式庫中的一個標頭檔,定義了C++標準中的字串的基本模板類std::basic_string及相關的模板類別實例:
模板類別實例 | std::basic_string的模板實參 |
---|---|
string |
char
|
wstring |
wchar_t
|
u16string |
char16_t (C++11新增)
|
u32string |
char32_t (C++11新增)
|
其中的string是以char作為模板參數的模板類別實例[1],把字串的主記憶體管理責任由string
負責而不是由編程者負責,大大減輕了C語言風格的字串的麻煩。
std::basic_string
提供了大量的字串操作函數,如比較、連接、搜尋、替換、獲得子串等。並可與C語言風格字串雙向轉換。std::basic_string
屬於C++ STL容器類,用戶自訂的類也可以作為它的模板參數,因此也適用C++ STL Algorithm庫。
string
本質上是以字元作為元素的vector特化版本;不存在0字元結尾這個概念,能裝入'\0'這種數據。
std::basic_string類別模板
std::basic_string
類別模板儲存且操縱類似char的對象的序列。該對象類型的性質由特性類別模板std::char_traits的實例來提供,並作為std::basic_string
的第二個模板參數。
C++11標準規定:basic_string的元素是連續儲存的。即對於basic_string s,有:&*(s.begin() + n) == &*s.begin() + n
,其中n屬於[0, s.size())。換句話說,指向s[0]的指標即為指向CharT[]陣列的首元素指標。C++11已經禁止了寫入時複製(copy-on-write)的實現,因為存在多線程安全問題。一般都採用了小字串最佳化(SSO)實現,如Visual C++:
union _Bxty
{ // storage for small buffer or pointer to larger one
_Elem _Buf[_BUF_SIZE];
_Elem *_Ptr;
} _Bx;
size_type _Mysize; // current length of string
size_type _Myres; // current storage reserved for string
GCC從版本5開始,std::string不再採用COW策略。
C++17標準規定,basic_string是AllocatorAwareContainer, SequenceContainer與ContiguousContainer。
- CharT - 字元類型
- Traits - 字元的特性類
- Allocator 內部儲存的分配器類
- traits_type 模板參數Traits
- value_type 即Traits::char_type
- allocator_type模板參數Allocator
- size_type 即Allocator::size_type。C++11改為std::allocator_traits<Allocator>::size_type
- difference_type即Allocator::difference_type。C++11改為std::allocator_traits<Allocator>::difference_type
- reference 即Allocator::reference。C++11改為value_type&
- const_reference 即Allocator::const_reference。C++11改為const value_type&
- pointer 即Allocator::pointer。C++11改為std::allocator_traits<Allocator>::pointer
- const_pointer 即Allocator::const_pointer。C++11改為std::allocator_traits<Allocator>::const_pointer
- iterator 屬於RandomAccessIterator
- const_iterator 屬於Constant random access iterator
- reverse_iterator 即std::reverse_iterator<iterator>
- const_reverse_iterator 即std::reverse_iterator<const_iterator>
下面列出所有成員函數,其中 string
是 std::basic_string<T>
的簡寫:
- 構造表示
string::string
(構造)string::~string
(解構)string::operator=
- 賦值string::assign
–賦值string::get_allocator
–獲得主記憶體分配器
- 字元訪問
- 迭代器
- 容量
- 修改器
string::clear
–清空內容string::insert
–插入字元或字串。目標 string 中的插入位置可用整數值或迭代器表示。如果參數僅為一個迭代器,則在其所指位置插入0 值。string::erase
–刪除 1 個或 1 段字元string::push_back
–追加 1 個字元string::pop_back
–刪除最後 1 個字元,C++11 標準引入string::append
–追加字元或字串string::operator+=
–追加,只有一個參數——字元指標、字元或字串;不像 append() 一樣可以追加參數的子串或若干相同字元string::copy
–拷貝出一段字元到 C 風格字元陣列;有溢位危險string::resize
–改變(增加或減少)字串長度;如果增加了字串長度,新字元預設為 0 值string::swap
–與另一個 string 交換內容string::replace
–替換子串;如果替換源數據與被替換數據的長度不等,則結果字串的長度發生改變
- 搜尋
string::find
–前向搜尋特定子串的第一次出現string::rfind
–從尾部開始,後向搜尋特定子串的第一次出現string::find_first_of
–搜尋指定字元集合中任意字元在 *this 中的第一次出現string::find_last_of
–搜尋指定字元集合中任意字元在 *this 中的最後一次出現string::find_first_not_of
–*this 中的不屬於指定字元集合的首個字元string::find_last_not_of
–*this 中的不屬於指定字元集合的末個字元string::compare
–與參數字串比較
string::npos
–表示「未找到」,值為static const unsigned -1
std::operator+
–字串連接std::operator!=
–不等比較std::operator==
–相等比較std::operator<
–小於比較std::operator<=
–小於等於比較std::operator>
–大於比較std::operator>=
–大於等於比較std::operator<<
–字串內容寫到輸出流中std::operator>>
–從輸入流中讀取一個字串std::getline
–從istream中讀入一行或一段字元到string中std::swap
–交換兩個string的內容。是std::swap演算法針對std::basic_string的特化版本std::stoi
–字串轉為整形std::stol
–字串轉為長整形std::stoll
–字串轉為長長整形std::stoul
–字串轉為無符號長整形std::stoull
–字串轉為無符號長長整形std::stof
–字串轉為單精度浮點形std::stod
–字串轉為雙精度浮點形std::stold
–字串轉為長雙精度浮點形std::to_string
–整型、無符號整型、浮點型轉化為stringstd::to_wstring
–整型、無符號整型、浮點型轉化為wstringstd::hash<std::string>
–計算hash值std::hash<std::wstring>
–計算hash值std::hash<std::u16string>
–計算hash值std::hash<std::u32string>
–計算hash值
C++14標準定義了如下的std::basic_string字面量:
- string operator "" s(const char *str, std::size_t len);
- u16string operator "" s(const char16_t *str, std::size_t len);
- u32string operator "" s(const char32_t *str, std::size_t len);
- wstring operator "" s(const wchar_t *str, std::size_t len);
範例:
#include <string>
#include <iostream>
int main()
{
using namespace std::string_literals;
std::string s2 = "abc\0\0def"; // forms the string "abc"
std::string s1 = "abc\0\0def"s; // form the string "abc\0\0def"
std::cout<<s1.size()<<std::endl; //output 8
std::cout<<s2<<std::endl;
std::cout<<s1<<std::endl;
}
C++11標準引入了4個std::hash函數模板的特化。用於以string為鍵值的hash定址。
- template<> struct hash<std::string>;
- template<> struct hash<std::wstring>;
- template<> struct hash<std::u16string>;
- template<> struct hash<std::u32string>;
std::char_traits類
char_traits是一個traits類別模板。用於抽象出給定字元類型的字元特性與字串操作。char_traits用於明確(explicit)實例化一個std::basic_string
類別模板。
- 成員類型
- char_type CharT
- int_type 可以保持char_type以及EOF的值的整數類型
- off_type 實現定義
- pos_type 實現定義
- state_type 實現定義
- 成員函數
- assign[static]賦值一個字元
- eq[static] 比較兩個字元相等
- lt[static] 比較兩個字元小於
- move[static] 移動一個字元序列到另一個字元序列
- copy[static] 複製一個字元序列
- compare[static]詞典序比較兩個字元序列
- length[static]返回一個字元序列的長度
- find[static] 在一個字元序列中找到一個字元
- to_char_type[static]轉化整型值到相等的char_type
- to_int_type[static] 轉化char_type到相等的整型值
- eq_int_type[static] 比較兩個整型值
- eof[static] 返回eof值
- not_eof[static]檢查一個字元是否為eof值
例如,如果需要定義「兩個字元相等」若且唯若「兩個字元的大寫形式相等」,就可以在std::char_traits<char>之上衍生定義一個類,多載定義eq、lt、compare、find四個靜態成員函數。再用此特性類作為第二個模板參數去實例化std::basic_string類別模板。
C++11放棄了COW
從C++11開始,明確禁止用「寫時複製」(Copy On Write)實現stl::string。因為這在並行時容易引發錯誤。如下例的註釋:
#include <string>
int main()
{
std::string str1("hello world\n");
//p指向str1的数据区
const char * p = str1.data();
{
//str2和str1共享数据
auto str2( str1);
//访问导致str1复制数据,此时p和str2直线同一块区域
str1[0];
//str2离开作用域,调用析构函数,此时str2的RefCount为0,因此str2指向的内存被释放
}
//此时p为野指针,这是严重的bug
printf(p);
return 0;
}
小對象最佳化
現在的主流編譯器與標準庫基本都採用了小對象最佳化(small objects optimization,又叫 small buffer optimization),以節約動態分配主記憶體開銷。
- Visual C++:0至15個位元組。在release版中,小字串緩衝區和儲存區指標復用為一個union,再加上數據長度、數據區總長度,共計24個位元組(32位元非寬字元)或32個位元組(64位元非寬字元);在debug中,小字串緩衝區和儲存區指標各有自己的儲存空間,因為共計28個位元組(32位元非寬字元)或40個位元組(64位元非寬字元)。
- GCC >= 5:0至15個位元組
- clang::0至22個位元組
用法
#include <iostream>
#include <string>
int main()
{
std::string foo = "fighters";
std::string bar = "stool";
// "!=" compares string contents for inequality, even though they are different objects.
if(foo != bar)
{
std::cout << "The strings are different." << std::endl;
}
// Prints "stool fighters" by creating a temporary object, which is automatically freed.
std::cout << bar + " " + foo << std::endl;
return 0;
}
/*
Output:
The strings are different.
stool fighters
*/
由於字串的拷貝操作與其位元組長度成比例,是O(n)量級。且建立字串的臨時棧對象的成本開銷。因此string
一般作為常數參照(reference-to-const)以避免不必要的拷貝:
void print_the_string(const std::string& str)
{
std::cout << str;
}
c_str()
成員函數返回string類的C語言風格字串(即ASCII-零串)的指標,用於C語言字串的互操作。如果不需要零結尾的字串,那麼成員函數data()
返回不一定是0結尾的字串的主記憶體地址。
參考文獻
Wikiwand in your browser!
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.