c ++ std :: ostringstream vs std :: string :: append

时间:2013-11-07 19:25:27

标签: c++ string stream

在使用某种缓冲的所有示例中,我看到它们使用流而不是字符串。 std :: ostringstream和<<运算符与使用string.append不同。哪一个更快,哪一个使用更少的资源(记忆)。

我知道的一个区别是你可以输出不同的类型到输出流(如整数),而不是字符串:: append接受的有限类型。

以下是一个例子:

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

显然使用stream的时间较短,但我认为append会返回对字符串的引用,因此可以这样写:

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

使用输出流,您可以执行以下操作:

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

但是内存使用和速度呢?特别是在大循环中使用时。

更新

更清楚的问题是:我应该使用哪一个?为什么?是否存在首选或其他的情况?对于性能和记忆......我认为基准是唯一的方法,因为每个实现都可能不同。

更新2:

嗯,我不清楚我应该从答案中使用什么,这意味着他们中的任何一个都会完成这项任务,再加上矢量。 Cubbi做了很好的基准,加上DietmarKühl,最大的不同是这些物体的构造。如果您正在寻找答案,您也应该检查一下。我会等待更多的其他答案(看看以前的更新),如果我没有得到一个,我想我会接受Tolga的答案,因为他的建议使用矢量已经完成之前意味着矢量应该是更少的资源饥饿。

4 个答案:

答案 0 :(得分:21)

构造流对象是一个比构造一个字符串对象更复杂的操作,因为它必须保存(并因此构造)其std::locale成员,以及其他需要的东西保持状态(但是区域设置是最大的边界)。

追加类似:两者都维持一个连续的字符数组,当超出容量时分配更多。我能想到的唯一区别是,当附加到流时,每次溢出都有一个虚拟成员函数调用(除了内存分配/复制,无论如何都支配溢出处理),而operator<<必须做一些额外检查流状态。

另外,请注意,您正在调用str(),它会再次复制整个字符串,因此根据您的代码编写的内容,流示例会做得更多,而且应该更慢。

让我们测试一下:

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

1000万次重复

在我的Linux上,我得到了

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

所以,对于这个用例,在这两个实现中,字符串似乎工作得更快,但显然两种方式都有很多改进(保留()字符串,将流构造移出循环,使用不包含的流#39; t要求复制以访问其缓冲区等)

答案 1 :(得分:10)

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

在这种情况下,使用适当的std::string

std::string::reserve没有理由采取比std::ostringstream更慢的行动。

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

P.S。 Pre-C ++ 11 std::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实现足够好的操作。

在选择时,满足您需求和最小额外功能的容器通常可以最好地完成工作。

答案 2 :(得分:1)

使用流,您可以让您的班级Myclass覆盖<<操作,以便您可以编写

MyClass x;
ostringstream y;
y << x;

对于append,你需要有一个ToString方法(或类似的东西),因为你不能覆盖string的append函数。

对于某些代码,请使用您感觉更舒服的任何内容。 将流用于更大的项目,只需简单地流式传输对象即可。

答案 3 :(得分:0)

如果您关心速度,则应进行剖析和/或测试。理论上std::string::append应该不慢,因为它更简单(流必须处理区域设置,不同的格式并且更通用)。但是,只有通过测试才能实现一个或另一个解决方案的速度。