我对C++的字符串不太熟悉。有没有办法一次连接多个字符串?还是只能每次连接两个字符串?我的担心是每次操作可能需要分配内存,而不是仅在最终结果中分配一次。
我记得Java里有类似的功能,不知道std库中是否有类似的方法。实际上,std::stringstream可能就是这种方法,但我不知道它的具体用法。
保留
所需的空间,避免重新分配。std::string s0{/*...*/}, s1{/*...*/}, s2{/*...*/};
std::string sink;
sink.reserve(s0.size() + s1.size() + s2.size() + 1);
sink += s0;
sink += s1;
sink += s2;
您可以使用可变参数的 string_cat
函数使其更加简洁。这是 C++17 的实现:
template <typename... Strings>
std::string string_cat(Strings&&... strings)
{
std::string result;
result.reserve((strings.size() + ...) + 1);
((result += std::forward<Strings>(strings)), ...);
return result;
}
使用方法:
using namespace std::literals;
auto res = string_cat("a"s, "b"s, "c"s);
为避免昂贵的内存浪费,请使用 stringstream
。
std::stringstream
可能是这个,但我不知道它具体的工作原理。
它的工作方式如下:包含头文件 sstream,创建一个对象,使用流运算符<< 将需要的内容添加到对象中,使用函数 str 将结果作为字符串获取。
例如:
#include <sstream>
std::stringstream mySS;
mySS << "Hello" << " World!" << "end!!" << " Foo";
std::string stringResult = mySS.str();
您说得对,每个字符串拼接可能需要分配内存。考虑以下表达式,其中每个变量都是一个字符串:
a = b + c + d + e;
这需要三个连接操作和三个临时变量,每个都需要新的分配。
一个简单的解决方案是使用 std::ostringstream
,它不应该需要太多重新分配:
std::ostringstream ss;
ss << b << c << d << e;
a = ss.str();
然而,如果我们只是要连接字符串,我们可以更好地分配恰好合适的字符串大小(符合 C++11 标准实现):
std::size_t total_string_size()
{
return 1;
}
template <typename... T>
std::size_t total_string_size(std::string const &s, T const & ...tail)
{
return s.size() + total_string_size(tail...);
}
void concat_strings_impl(std::string &) { }
template <typename... T>
void concat_strings_impl(std::string &out, std::string const &s, T const & ...tail)
{
out += s;
concat_strings_impl(out, tail...);
}
template <typename... T>
void concat_strings(std::string &out, T const & ...strings)
{
out.clear();
out.reserve(total_string_size(strings...));
concat_strings_impl(out, strings...);
}
concat_strings(a, b, c, d, e)
,以单个重新分配的方式执行与a = b + c + d + e;
等效的操作。(演示)std::stringstream
不会使用太多的内存分配? - Galikstd::vector
一样分配一些额外的空间,而简单的+
连接操作则需要为字符串临时变量进行新的分配。因此,更准确地说,stringstream不需要更多的重新分配,但通常应该需要更少的重新分配。 - cdhowie避免多次分配内存的唯一方法是在连接字符串之前告诉字符串需要变成多大。
例如,将存储在向量(类似于列表)中的所有字符串连接起来:
std::string join(std::vector<std::string> const& v)
{
std::string r; // return string
// add up all the string sizes
std::size_t size = 0;
for(auto const& s: v)
size += s.size();
// reserve that much space all at once (one allocation)
r.reserve(size);
// now do the concatenations
for(auto const& s: v)
r += s;
return r;
}
char*
),那么您可以分配一次并连接多次。函数strcat
将指向目标地址的指针作为第一个参数。因此,如果您使目标字符串足够大,则只需要进行一次分配。因此,char* dest = new char[100];
dest[0] = 0; //Zero length string to start
strcat(dest, str1);
strcat(dest, str2);
strcat(dest, str3);
std::string
,那么可以链接使用 +
,例如 string1 + string2 + string3
。你可以连接多个字符串 - 没有问题:
std::string hello = "Hello";
std::string cruel = "cruel";
std::string world = "world";
std::string result = hello + " " + cruel + " " + world;
result
中存储了字符串 "Hello cruel world"。
operator +
:auto foo = string1 + string2 + "some text" + string3;
- NathanOliver