49

In all examples that use some kind of buffering I see they use stream instead of string. How is std::ostringstream and << operator different than using string.append. Which one is faster and which one uses less resourses (memory).

One difference I know is that you can output different types into output stream (like integer) rather than the limited types that string::append accepts.

Here is an example:

std::ostringstream os;
os << "Content-Type: " << contentType << ";charset=" << charset << "\r\n";
std::string header = os.str();

vs

std::string header("Content-Type: ");
header.append(contentType);
header.append(";charset=");
header.append(charset);
header.append("\r\n");

Obviously using stream is shorter, but I think append returns reference to the string so it can be written like this:

std::string header("Content-Type: ");
header.append(contentType)
  .append(";charset=")
  .append(charset)
  .append("\r\n");

And with output stream you can do:

std::string content;
...
os << "Content-Length: " << content.length() << "\r\n";

But what about memory usage and speed? Especially when used in a big loop.

Update:

To be more clear the question is: Which one should I use and why? Is there situations when one is preferred or the other? For performance and memory ... well I think benchmark is the only way since every implementation could be different.

Update 2:

Well I don't get clear idea what should I use from the answers which means that any of them will do the job, plus vector. Cubbi did nice benchmark with the addition of Dietmar Kühl that the biggest difference is construction of those objects. If you are looking for an answer you should check that too. I'll wait a bit more for other answers (look previous update) and if I don't get one I think I'll accept Tolga's answer because his suggestion to use vector is already done before which means vector should be less resource hungry.

4

4 回答 4

33

constructing a stream object is a significantly more complex operation than constructing a string object, because it has to hold (and, therefore, construct) its std::locale member, among other things needed to maintain state (but the locale is by a large margin the heaviest).

Appending is similar: both maintain a contiguous array of characters, both allocate more when the capacity is exceeded. The only differences I can think of is that when appending to a stream, there is one virtual member function call per overflow (in addition to memory allocation/copying, which dominates overflow handling anyway), and operator<< has to do some extra checks of the stream state.

Also, note that you're calling str(), which copies the entire string one more time, so based on what your code is written to do, the stream example does more and should be slower.

Let's test:

#include <sstream>
#include <string>
#include <numeric>

volatile unsigned int sink;
std::string contentType(50, ' ');
std::string charset(50, ' ');
int main()
{
 for(long n = 0; n < 10000000; ++n)
 {
#ifdef TEST_STREAM    
    std::ostringstream os;
    os << "Content-Type: " << contentType << ";charset=" << charset << "\r\n";
    std::string header = os.str();
#endif
#ifdef TEST_STRING
    std::string header("Content-Type: ");
    header.append(contentType);
    header.append(";charset=");
    header.append(charset);
    header.append("\r\n");
#endif
    sink += std::accumulate(header.begin(), header.end(), 0);
 }
}

that's 10 million repetitions

On my Linux, I get

                   stream         string
g++ 4.8          7.9 seconds      4.4 seconds
clang++/libc++  11.3 seconds      3.3 seconds

so, for this use case, in these two implementations, strings appear to work faster, but obviously both ways have a lot to improve (reserve() the string, move stream construction out of the loop, use a stream that doesn't require copying to access its buffer, etc)

于 2013-11-07T20:05:02.840 回答
17

std::ostringstream不一定存储为内存中的连续字符数组。在发送这些 HTTP 标头时,您实际上需要有连续的字符数组,这可能会复制/修改内部缓冲区以使其连续。

std::string使用适当std::string::reserve的没有理由比std::ostringstream在这种情况下行动慢。

但是,std::ostringstream如果您完全不知道必须保留的大小,则附加可能会更快。如果您使用std::string并且您的字符串增长,它最终需要重新分配和复制整个缓冲区。std::ostringstream::str()与其他情况下会发生的多次重新分配相比,最好使用一次来使数据顺序化。

PS Pre-C++11std::string也不需要是顺序的,而几乎所有的库都将它实现为顺序的。您可以冒险或使用它std::vector<char>。您需要使用以下内容进行附加:

char str[] = ";charset=";
vector.insert(vector.end(), str, str + sizeof(str) - 1);

std::vector<char>对性能来说是最好的,因为它很可能构建起来更便宜,但与std::string它们构建的实际时间相比,它可能并不重要。我做了一些类似于你std::vector<char>之前尝试过的事情。纯粹是因为逻辑上的原因;矢量似乎更适合这项工作。您实际上并不想要字符串操作等。此外,我后来做的基准测试证明它表现得更好,或者可能只是因为我没有很好地使用std::string.

在选择时,具有您的需求和最少额外功能的容器通常可以做得最好。

于 2013-11-07T19:38:14.390 回答
1

With stream you can have your class Myclass override the << operation so that you can write

MyClass x;
ostringstream y;
y << x;

For append you need to have a ToString method (or something similar) since you can't override the append function of string.

For some code pieces use whatever you feel more comfortable with. Use stream for bigger projects where it's useful to be able to simply stream an object.

于 2013-11-07T19:55:14.743 回答
0

如果您关心速度,您应该配置和/或测试。理论上std::string::append不应该更慢,因为它更简单(流必须处理语言环境、不同的格式并且更通用)。但是,只有通过测试才能意识到一种或另一种解决方案的速度到底有多快。

于 2013-11-07T19:33:43.623 回答