2009-01-15 70 views

回答

25

std::ostringstream不是要求要慢一些,但实施时一般比较慢。 FastFormat's website has some benchmarks

流的标准库设计支持远远超过snprintf。该设计旨在具有可扩展性,并且包含由公开公开方法调用的方法。这允许你从一个流类派生出来,并保证如果你超载了protect ed方法,你将得到你想要的行为。我相信编译器可以避免virtual函数调用的开销,但我不知道有任何编译器。

此外,流操作通常在内部使用可增长的缓冲区;这意味着相对较慢的内存分配。

+0

哇 - 我有一段时间没去过马修威尔逊的网站 - 看起来他过去几个月都很忙... – 2009-01-15 01:52:18

+0

FastFormat测试是有偏见的。下载代码后,您会看到snprintf()基准测试会调用一个名为fastformat_util_snprintf()的函数,该函数包含一些可能会抛出测试的包装代码。但是你是对的,内存管理可能是ostringstream变慢的原因。 – Max 2009-01-16 11:13:26

+0

感谢您查看代码。我只看过漂亮的图表。 – 2009-01-20 09:10:05

0

这很有可能是因为sprintf是用汇编编写的CRT的一部分。 ostringstream是STL的一部分,可能更通用一些,并且有OOP代码/开销来处理。

+3

我非常强烈地怀疑有人在汇编中实现了`sprintf`,除了可能作为一个练习受虐狂。一直回到UNIX V6,C运行时库本身已经被编写成C语言(除了一些很少用C语言编写的东西,比如`setjmp`)。 – zwol 2012-09-19 15:42:09

3

绝对这是特定于实现的。

但是,如果你真的想知道,写两个小程序,并比较它们。您需要包含您想要的典型用法,这两个程序需要生成相同的字符串,然后使用分析器查看时序信息。

然后你就会知道。

0

我知道printf家族函数比相应的C++函数(cout,cin和其他流)快的原因之一是后者进行类型检查。由于这通常涉及一些重载操作员的请求,因此可能需要一些时间。实际上,在编程竞赛中,为了这个原因,通常建议您使用printf等而不是cout/cin。

8

有些人可能会告诉你,函数不能比彼此更快,但他们的实现可以。这是对的,我想我会同意。

除了基准以外,您不可能注意到其中的差异。 C++流一般趋于的原因是它们更加灵活。灵活性通常是以时间或代码增长为代价的。

在这种情况下,C++流基于流缓冲区。流本身就是保持格式化和错误标志的地方,并调用C++标准库的正确i/o构面(例如,用于打印数字的num_put),将值格式化良好的值打印到基础流中连接到C++流的缓冲区。

所有这些机制 - 方面和缓冲区都是通过虚函数实现的。虽然确实没有标记请注意,这些函数必须被实现为比cStdio挂件慢,这实际上会使它们比通常使用c stdio函数稍慢(我基准了一段时间之前用gcc/libstdC++和事实上注意到一个放缓 - 但你几乎没有注意到在日常使用)。

1

有一个问题可能是由ostringstream增加的类型安全带来额外的开销。不过,我还没有做过任何测量。

8

我们用sprintf(使用静态分配的缓冲区)替换了内部循环中的一些stringstream,这在msvc和gcc中都有很大的不同。我想,这个代码的动态内存管理:

 
{ 
    char buf[100]; 
    int i = 100; 
    sprintf(buf, "%d", i); 
    // do something with buf 
} 

 
{ 
    std::stringstream ss; 
    int i = 100; 
    ss << i; 
    std::string s = ss.str(); 
    // do something with s 
} 

简单多了,但我很高兴与stringstreams的整体性能。

0

作为litb said,标准流支持许多我们并不总是需要的东西。 有些流实现摆脱了这个从未使用的灵活性,例如参见FAStream

0

是的,如果你用Visual C++ 5.0在几百万个数字上运行下面的函数,第一个版本的时间大约是第二个版本的两倍,并产生相同的输出。

将紧密循环编译为.exe文件并运行Windows时,“我是如何调查大多数性能好奇心的。 (`timethis'可在网上找到)

void Hex32Bit(unsigned int n, string &result) 
{ 
#if 0 
    stringstream ss; 
    ss 
     << hex 
     << setfill('0') 
     << "0x" << setw(8) << n 
    ; 
    result = ss.str(); 
#else 
    const size_t len = 11; 
    char temp[len]; 
    _snprintf(temp, len, "0x%08x", n); 
    temp[len - 1] = '\0'; 
    result = temp; 
#endif 
}