2017-06-06 43 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; 
}