std::string_view
是std::basic_string_view<char>
的别名,它是一个以特定字符类型char
为模板参数的std::basic_string_view
。
那么它长什么样呢?
除了有一些有用的成员函数(例如find
、substr
等),其数量与STL提供的其他容器/类似字符串的东西相比可能还算普通,std::basic_string_view<_CharT>
只有两个数据成员,其中_CharT
是通用的char
-like类型。
size_t _M_len;
const _CharT* _M_str;
即一个指向_CharT
的常量指针,用于表示视图的起始位置,和一个size_t
(一种适当类型的数字),用于表示从_M_str
的指针开始视图的长度。
换句话说,字符串视图只知道它在哪里开始以及它有多长,因此它表示了内存中连续的类似于char
实体的序列。仅凭两个成员,您无法表示由非连续子字符串组成的字符串。
换言之,如果要创建std::string_view
,则需要能够告诉它有多少个char
并且从哪个位置开始。您能告诉s1 + s2
应该从哪里开始,并且长度应该是多少吗?好好想想:您不能,因为s1
和s2
不是相邻的。
也许一个图可以帮助理解。
假设有以下代码行:
std::string s1{"hello"};
std::string s2{"world"};
s1
和s2
在内存位置上完全没有关联,它们看起来是这样的:
&s2[0]
|
| &s2[1]
| |
&s1[0] | | &s2[2]
| | | |
| &s1[1] | | | &s2[3]
| | | | | |
| | &s1[2] | | | | &s2[4]
| | | | | | | |
| | | &s1[3] v v v v v
| | | | +---+---+---+---+---+
| | | | &s1[4] | w | o | r | l | d |
| | | | | +---+---+---+---+---+
v v v v v
+---+---+---+---+---+
| h | e | l | l | o |
+---+---+---+---+---+
我故意将它们绘制为不对齐的,这是为了说明&s1[0]
,也就是s1
开始的内存位置和&s2[0]
,也就是s2
开始的内存位置互不相关。
现在,想象你创建了两个字符串视图:
std::string_view sv1{s1};
std::string_view sv2(s2.begin() + 1, s2.begin() + 4);
下面是针对两个实现定义成员变量 _M_str
和 _M_len
的样例:
&s2[0]
|
| &s2[1]
| |
&s1[0] | | &s2[2]
| | | |
| &s1[1] | | | &s2[3]
| | | | | |
| | &s1[2] | | | | &s2[4]
| | | | | | | |
| | | &s1[3] v v v v v
| | | | +---+---+---+---+---+
| | | | &s1[4] | w | o | r | l | d |
| | | | | +---+---+---+---+---+
v v v v v · ^ ·
+---+---+---+---+---+ · | ·
| h | e | l | l | o | +---+ ·
+---+---+---+---+---+ | · ·
· ^ · | · s2._M_len ·
· | · | <----------->
+---+ · |
| · · +-- s2._M_str
| · s1._M_len ·
| <------------------->
|
+-------- s1._M_str
考虑到以上情况,你能看出期望什么有什么问题吗?
std::string_view s3{s1 + s2};
这个方案可行吗?
如何基于s1._M_str
、s1._M_len
、s2._M_str
和s2._M_len
来定义s3._M_str
和s3._M_len
,使它们表示对"helloworld"
的视图?
不可能,因为"hello"
和"world"
在内存的两个不相关区域中。
string_view
不拥有数据,它必须存储在某个地方。如果要连接字符串,请使用std::string
。 - Ted Lyngmo