连接的字符串是如何分配的?

Rad*_*nyx 1 c++ memory string concatenation

我想知道字符串和内存如何一起工作。

据我所知,我知道当创建一个字符串时,它会将一些字符数组 + '\0' 放入内存中。我也知道它们是一成不变的。那么,对于连接之类的事情,内存中会发生什么,允许您访问相同的字符串?

我不认为您连接的字符串或字符直接放在原始字符串的地址之后,因为这可能会重叠一些所需的内存。

在 C# 和其他语言中,您可以说:

string s = "Hello" ... s = s + '!'

这会创建一个新字符串吗?一个指向一个新位置并显示“Hello!”,而使原始位置永远不会被引用的位置?

或者字符串使用的默认字符缓冲区是否允许连接中存在一些空间?

Who*_*aig 5

您所质疑的表达式的行为已由标准明确定义,并且是实现所必需遵循的。该标准的相关章节如下:

\n\n

C++11\xc2\xa7 21.4.8.1-11

\n\n
template<class charT, class traits, class Allocator> \n    basic_string<charT,traits,Allocator>\noperator+(const basic_string<charT,traits,Allocator>& lhs,\n          const charT* rhs);\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

返回:lhs + basic_string<charT,traits,Allocator>(rhs)

\n
\n\n

这导致:

\n\n

C++11\xc2\xa7 21.4.8.1-3

\n\n
template<class charT, class traits, class Allocator>\n    basic_string<charT,traits,Allocator>\noperator+(const basic_string<charT,traits,Allocator>& lhs,\n          basic_string<charT,traits,Allocator>&& rhs);\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

返回:std::move(rhs.insert(0, lhs))

\n
\n\n

最后...

\n\n

C++11\xc2\xa7 21.4.2-22

\n\n
basic_string<charT,traits,Allocator>&\n  operator=(basic_string<charT,traits,Allocator>&& str) noexcept;\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

效果:如果 *this 和 str 不是同一个对象,则按表 71 所示修改 *this。 [注意:有效的实现是 swap(str)。\xe2\x80\x94 结束\n 注意]

\n
\n\n

换句话说,为+运算符的 rhs 创建一个临时值,然后使用 修改该右值引用rhs.insert(0,lhs),最后将结果发送到赋值运算符的右值引用版本,该版本可以有效地执行移动操作。

\n\n

有关详细信息,请参阅该标准的相关部分。

\n\n
\n\n

C++03x 注释

\n\n

有人要求我为 C++03x 提供相同的演练。我对该标准的最后(官方)版本并不确定,但作为参考,以下内容基于 ISO/IEC 14882:2003(E)。请自行决定使用。

\n\n

还为 C++03x 定义了类似的演练,如下所述,并适当注明了标准的相关部分。

\n\n

C++03x \xc2\xa7 21.3.7.1-5

\n\n
template<class charT, class traits, class Allocator>\n             basic_string<charT,traits,Allocator>\noperator+(const basic_string<charT,traits,Allocator>& lhs, const charT* rhs);\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

返回:lhs + basic_string<charT,traits,Allocator>(rhs)

\n
\n\n

因此,与 C++11 一样,临时值是根据表达式的rhs构造的。从那里...

\n\n

C++03x \xc2\xa7 21.3.7.1-1

\n\n
template<class charT, class traits, class Allocator>\n             basic_string<charT,traits,Allocator>\noperator+(const basic_string<charT,traits,Allocator>& lhs, \n          const basic_string<charT,traits,Allocator>& rhs);\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

返回: basic_string(lhs).append(rhs)

\n
\n\n

这里我们与 C++11 不同。我们构造lhs的临时值,然后使用成员函数附加给定的rhs(第一步中的临时值)append()为了简洁起见,我省略了临时lhs的常量引用构造函数。这将我们带到......

\n\n

C++03x \xc2\xa7 21.3.5.2-1

\n\n
basic_string<charT,traits,Allocator>&\n  append(const basic_string<charT,traits>& str);\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

返回:append(str, 0, npos)

\n
\n\n

这会将调用转发到相关成员函数,该函数接受来自要枚举的 rhs 的起始和停止索引。这将我们带到...

\n\n

C++03x \xc2\xa7 21.3.5.2-2..5 \n basic_string&\n 追加(const basic_string& str, size_type pos, size_type n);

\n\n
\n

要求: pos <= str.size()

\n\n

抛出: out_of_range 如果 pos > str.size()。

\n\n

效果:确定要附加的字符串的有效长度 rlen,作为 n 和 str.size() - pos 中较小的一个。如果 size() >= npos - rlen,则该函数将抛出 length_error。否则,该函数将 *this 控制的字符串替换为长度为 size() + rlen 的字符串,其中第一个 size() 元素是 *this 控制的原始字符串的副本,其余元素是 *this 的初始元素的副本由 str 控制的字符串,从位置 pos 开始。

\n\n

返回:*这个。

\n
\n\n

本质上,这对位置参数进行一些健全性检查,然后用连接的内容执行替换。最后,现在完成了赋值操作,我们可以对整个失败的目标执行赋值操作,这将我们带到......

\n\n

C++03x \xc2\xa7 21.3.1-16

\n\n
basic_string<charT,traits,Allocator>&\n  operator=(const basic_string<charT,traits,Allocator>& str);\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

效果:如果 *this 和 str 不是同一个对象,则修改 *this 如表 43 所示

\n\n

返回:*这个

\n
\n\n

表43表示以下所需的效果。

\n\n
\n

data()- 指向数组的已分配副本的第一个元素,其第一个元素由str.data()

\n\n

size()- str.size()

\n\n

capacity()- 至少与size()

\n
\n\n

我对此的评估是,实施可以做它想做的事情来实现这些效果(在表 43 中;仍然需要此处所示的实施路径)。

\n\n

我太累了,无法继续学习 C++98。我希望这已经足够了。

\n