2017-06-06 83 views
2

我是C++字符串的新手。有没有办法一次连接两个以上的字符串?或者我必须在两个字符串连接?我担心的是,它可能需要为每个操作分配内存,而不是只为最终结果分配一次内存。一次Concat多个C++字符串?

在java中记住类似的东西,想知道std中是否有某种方法。实际上,std :: stringstream可能是它,但我不知道它是如何工作的。

+3

除非你有导致不(你异型,发现性能不合格),只要用'运营商+'像:'auto foo = string1 + string2 +“一些文本”+ string3;' – NathanOliver

+0

你只是想协调一堆随机字符串吗?如果是这样,那么只需使用“+”运算符。 –

回答

4

是,以避免昂贵的浪费内存使用stringstream

的std :: stringstream的可能是的,但我不知道它的工作原理。

这是它如何工作的:包括sstream,创建一个对象,附加到它,就像你需要用流运算符< <得到的结果作为字符串调用函数STR

例如:

#include <sstream> 
std::stringstream mySS; 

mySS << "Hello" << " World!" << "end!!" << " Foo"; 

,当你完成

std::string stringResult = mySS.str(); 
+0

因此,它实际上保持所有字符串,直到.str()调用?这是我想知道的。谢谢。 –

+0

确切地说,你追加和追加的东西,直到你需要它,然后调用str()....或多或少像在Java中的StringBuilder .... –

+0

对不起,有一个额外的问题,我不知道怎么才能真正检查它是否像那样工作。在调试器中打开它我猜? –

5

您可以在reserve之前预先留出必要的空间,避免重新分配。

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); 

live example on wandbox

1

可以连接多个字符串 - 没问题:

std::string hello = "Hello"; 
std::string cruel = "cruel"; 
std::string world = "world"; 
std::string result = hello + " " + cruel + " " + world; 

结果result持有字符串 “Hello残酷的世界”。

1

如果您使用的是C风格的字符串(即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

+0

看起来他的问题是关于多重连接的表现 - 它是否为链中的每个步骤创建了一个新的中间字符串,而不是一次将它们全部组合起来? – Barmar

+0

当心[Schlemiel the Painter](https://en.wikichip.org/wiki/schlemiel_the_painter%27s_algorithm)。 –

2

你是正确的,每个连接可能需要分配。考虑这样一个表达式,其中每个变量是一个字符串:

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;等效。 (Demo

+0

是什么让你认为'std :: stringstream'没有使用这么多的分配? – Galik

+0

@Galik我的意思是重新分配。它应该像'std :: vector'那样分配一些额外的空间,而一个简单的'+'连接操作*需要一个临时字符串的新分配。所以,比较准确地说,stringstream不需要更多的重新分配,但通常需要更少的重新分配。 – cdhowie

2

避免多次分配的唯一方法是告诉字符串在连接之前需要变得有多大。

例如,一起加入存储在向量的所有字符串(如列表):

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; 
}