如何分配串联字符串
How are concatenated strings allocated?
我想知道字符串和内存是如何协同工作的
据我所知,我知道当创建一个字符串时,它会将一些字符数组+"\0"放入内存。我也知道它们是不可变的。那么,对于串联之类的事情,内存中会发生什么,从而允许您访问相同的字符串
我不认为连接的字符串或字符会直接放在原始字符串的地址后面,因为这可能会与一些所需的内存重叠
在C#和其他语言中,您可以说:
string s = "Hello"
...
s = s + '!'
这会创建一个新字符串吗?一个指向一个新位置,上面写着"你好!",让原来的位置永远不会被引用?
或者字符串使用的默认字符缓冲区是否允许在串联中留出一些空间?
您所质疑的表达式的行为是由标准定义的,并且是实现所必需的。该标准的相关章节如下:
C++11§21.4.8.1-11
template<class charT, class traits, class Allocator>
basic_string<charT,traits,Allocator>
operator+(const basic_string<charT,traits,Allocator>& lhs,
const charT* rhs);
返回:
lhs + basic_string<charT,traits,Allocator>(rhs)
这导致:
C++11§21.4.8.1-3
template<class charT, class traits, class Allocator>
basic_string<charT,traits,Allocator>
operator+(const basic_string<charT,traits,Allocator>& lhs,
basic_string<charT,traits,Allocator>&& rhs);
返回:
std::move(rhs.insert(0, lhs))
最后。。。
C++11§21.4.2-22
basic_string<charT,traits,Allocator>&
operator=(basic_string<charT,traits,Allocator>&& str) noexcept;
效果:如果*this和str不是同一个对象,则将*this修改为如表71所示。[注意:有效的实现是swap(str)。--end注]
换句话说,为+
运算符的rhs创建一个临时值,然后使用rhs.insert(0,lhs)
修改该右值引用,最后,将结果发送到赋值运算符的右值引用版本,该版本可以有效地执行移动操作。
有关更多信息,请参阅该标准的相关章节。
C++03x Notes
有人要求我为C++03x提供相同的演练。我对该标准的最后(官方)版本不确定,但为了参考,以下内容基于ISO/IEC 14882:2003(E)。自行使用。
C++03x也定义了类似的通道,如下所述,并适当注明了标准的相关章节。
C++03x§21.3.7.1-5
template<class charT, class traits, class Allocator>
basic_string<charT,traits,Allocator>
operator+(const basic_string<charT,traits,Allocator>& lhs, const charT* rhs);
返回:
lhs + basic_string<charT,traits,Allocator>(rhs)
因此,与C++11一样,临时表达式是由表达式的rhs构造的。从那里。。。
C++03x§21.3.7.1-1
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);
返回:basic_string(lhs).append(rhs)
这里我们与C++11不同。我们构造lhs的临时,然后使用append()
成员函数附加给定的rhs[第一步中的临时]。为了简洁起见,我省略了lhs的临时const引用构造函数。这把我们带到…
C++03x§21.3.5.2-1
basic_string<charT,traits,Allocator>&
append(const basic_string<charT,traits>& str);
返回:
append(str, 0, npos)
这将调用转发到相关的成员函数,该函数接受要枚举的rhs的开始索引和停止索引。这将带我们去…
C++03x§21.3.5.2-2..5basic_ string&append(const basic_string&str,size_type pos,sizetype n);
需要:pos<=str.size()
抛出:如果pos>str.size(),则抛出out_of_range。
效果:将要附加的字符串的有效长度rlen确定为n和str.size()-pos中较小的一个。如果size()>=npos-rlen,则函数会抛出length_error。否则,函数将*this控制的字符串替换为长度为size()+rlen的字符串,该字符串的第一个size()元素是*this控制的原始字符串的副本,其余元素是从位置开始的str控制的字符串的初始元素的副本
返回:*this。
本质上,这会对位置参数进行一些健全性检查,然后用连接的内容执行替换。最后,现在已经完成了任务的rhs,我们可以对整个惨败的目标执行任务操作,这将带我们去…
C++03x§21.3.1-16
basic_string<charT,traits,Allocator>&
operator=(const basic_string<charT,traits,Allocator>& str);
效果:如果*this和str不是同一个对象,则修改*this,如表-43 所示
返回:*此
表43表示以下所需效果。
data()
-指向str.data()
指向其第一个元素的阵列的已分配副本的第一个元素
size()
-str.size()
capacity()
-至少与size()
一样大
我的评估是,实施可以随心所欲地实现这些效果(在表43中;这里所示的实施路径仍然是必需的)。
我太累了,没法开车进入C++98。我希望这已经足够了。
正如评论中所指出的,std::string
并不是一成不变的。
在字符串中使用+运算符时,如s + '!'
中所示,将创建一个新的临时字符串,其中包含结果。s = s + '!'
将此临时字符串复制回原始s
,替换原始文本。这就是不可变字符串在其他语言中的工作方式。
当您使用+=运算符或append函数时,会修改字符串,并将额外的字符添加到同一字符串对象中。但是,如果旧的内存缓冲区不够大,则可能会在内部分配新的内存缓冲。在重新分配时,通常会请求一些额外的空间,以允许在不重新分配的情况下进行小的未来追加(更高效)。您可以选择使用reserve函数来增加内部缓冲区的最小大小。如果您知道要追加多少数据,这会更有效。
在C++11之前,它依赖于实现。然而,与使用+
相比,使用+=
时库优化的机会要大得多。最大的区别是C++11现在指定(并强制)这些优化。
一般规则(包括过去、现在和未来的语言规范,甚至类似的语言)是:始终更喜欢
s+= "!" ;
代替您使用的示例代码。
原因是string
不是语言原语。它们只是另一种"用户"类型(编译器附带了这种类型,但那是另一回事)。当你写
s = s + "!" ;
调用类CCD_ 25的CCD_。然而,它被迫创建一个新对象(可能与s
共享一些存储),因为您本可以在其他上下文中使用它:
t = s + "!" ;
相反,+=
方法可以确保您希望附加到当前字符串,从而优化一个位(例如:使用内部缓冲区中的可用空间)。
- 我如何通过引用将 c++ 字符串分配给另一个字符串
- 无法在 c++ 中将字符串分配给字符串数据类型
- 将字符串* 分配给字符* c++
- 如何为C++字符串分配空指针参数?
- 为什么在构造函数中将字符串分配给指针是安全的?
- 如何将wchar_t字符串分配给用户定义类的 CString 成员
- 字符串分配
- 如何将字符串分配给向量(均在堆上)
- 确实为其写入的字符串分配内存
- 简单的字符串分配导致分割故障
- 通过新行不使用字符串流将C 字符串分配
- 将字符串分配到动态数组位置时出错
- 在 c++ 中为字符串分配其分配的大小值是否正确
- 从被空间分开的字符串分配给变量?C [QT]
- 将字符串分配给固定长度的字符数组
- 将一组字符串分配给向量c++的内容
- 如何为字符串分配内存
- C++中的字符串分配:为什么这样做
- 视觉 建议在C++中执行字符串分配什么?
- 字符 *str;str= "HELLO" ;如何在不为字符串分配任何内存的情况下工作?