我应该切换到C++ I/O流吗?

Mat*_*att 12 c++ iostream

我从来没有太多使用C++ I/O流,并且总是选择我所知道的.即printf功能.

我知道使用I/O流有一些好处,但我正在寻找stackoverflow社区的一些技巧来帮助我(或说服我)切换.因为我仍然更喜欢printf,我认为printf样式更容易阅读和更快速的输入.

即使我仍然继续使用printf,我仍然希望熟悉它.


编辑.有趣的是,谷歌C++编码风格禁止使用除日志记录之外的流.请参阅:http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml

仅使用流进行日志记录.定义:Streams是printf()和scanf()的替代品.

优点:使用流,您不需要知道要打印的对象的类型.格式字符串与参数列表不匹配时没有问题.(虽然使用gcc,你也没有printf的那个问题.)Streams有自动构造函数和析构函数来打开和关闭相关文件.

缺点:Streams使得难以执行pread()等功能.一些格式化(特别是常见格式字符串成语%.*s)即使不是不可能有效地使用流而不使用类似printf的黑客也是困难的.Streams不支持运算符重新排序(%1s指令),这有助于国际化.

决策:除了日志记录界面要求之外,不要使用流.请改用类似printf的例程.

使用流有各种各样的利弊,但在这种情况下,与许多其他情况一样,一致性胜过辩论.不要在代码中使用流.

扩展讨论

关于这个问题一直存在争议,因此这更深入地解释了推理.回想一下唯一的方法指导原则:我们希望确保每当我们执行某种类型的I/O时,代码在所有这些地方看起来都是一样的.因此,我们不希望允许用户在使用流或使用printf和读/写/等之间做出决定.相反,我们应该选择其中一个.我们为日志记录做了例外,因为它是一个非常专业的应用程序,并且由于历史原因.

流的支持者认为流是两者中明显的选择,但问题实际上并不那么清楚.他们指出,对于流的每个优点,都存在同样的缺点.最大的优点是您不需要知道要打印的对象的类型.这是一个公平的观点.但是,有一个缺点:你可以轻松使用错误的类型,编译器不会警告你.在不知道何时使用流的情况下很容易犯这种错误.

cout << this;  // Prints the address 
cout << *this;  // Prints the contents 
Run Code Online (Sandbox Code Playgroud)

编译器不会生成错误,因为<<已经过载.出于这个原因,我们不鼓励超载.

有人说printf格式是丑陋的,难以阅读,但流通常不会更好.考虑以下两个片段,两者都有相同的拼写错误.哪个更容易发现?

cerr << "Error connecting to '" << foo->bar()->hostname.first
     << ":" << foo->bar()->hostname.second << ": " << strerror(errno);
fprintf(stderr, "Error connecting to '%s:%u: %s",
      foo->bar()->hostname.first, foo->bar()->hostname.second,
      strerror(errno)); 
Run Code Online (Sandbox Code Playgroud)

对于您可能提出的任何问题,等等等等.(你可以争辩说,"使用合适的包装器会更好",但如果对于一个方案是真的,对另一个方案是否也是如此?另外,请记住,目标是使语言更小,而不是添加更多有人必须学习的机器.)

这两种方式都会产生不同的优点和缺点,并且没有明显优越的解决方案.简单原则要求我们决定其中一个,并且多数决定是关于printf +读/写.

Edw*_*nge 8

使用boost :: format.它是两全其美的.

  • 当然,减去性能.但是,是的,否则,它是两个世界中最好的. (6认同)

Pup*_*ppy 7

iostream提供的巨大优势是安全性.printf()本质上是不安全的函数.不仅仅是这样,但是对于你自己的类型重载<<是微不足道的,而实际上不可能扩展printf() - 这具有即时重载输出到文件以及连接到流的任何其他东西的附加优点.这些组合使得printf()在高质量代码中无法使用.我也注意到完全没有性能差异,虽然我看到很多人发布他们的速度有多慢.


ice*_*ime 7

我自己不是溪流的大用户,所以我只会列出我对它们的看法.这是非常主观的,如果我的答案被投票删除,我会理解.

  • 我喜欢:同质性

我可能有一个enum,一个class或其他任何东西,使我的用户定义类型可打印总是通过提供operator<<我的类型旁边相同:

std::ostream &operator<<(std::ostream &, const MyType &);
Run Code Online (Sandbox Code Playgroud)

你可能会问自己,如果一个类型是打印的,但从来没有怎么它是可打印.

  • 我喜欢:抽象

显然,向用户定义的类型提供"流式传输容量"非常容易.能够提供我们自己的流实现并使其透明地适合现有代码也是一件很棒的事.一旦operator<<适当地定义了,写入标准输出,内存缓冲区或文件就可以轻易改变.

  • 我不喜欢:格式化

我一直以为iomanip是一团糟.我讨厌写一些东西(我只是在这里投掷随机操纵器):

std::cout << std::left << std::fixed << std::setprecision(0) << f << std::endl;
Run Code Online (Sandbox Code Playgroud)

我认为它更容易printf,但Boost.Format在这里很有帮助.


Joh*_*ing 5

@Matt,我和你在一起.我一直讨厌溪流.当然,我可以使用它们.让他们做我想做的任何事情.但我喜欢printf因为我更喜欢语法.

我甚至写了一个strprintf完全相同的工作,sprintf除了返回一个std::string而不是写入一个char缓冲区.

但渐渐地,不情愿地,我几乎完全停止使用sprintf.因为,简单来说,我写了太多该死的错误,我厌倦了一次又一次地错过了同样的错误. stringstream安全类型让我远离我自己.

我正在谈论的错误有两种形式,主要是:

  1. 我为输出缓冲区选择了错误的幻数.说我想出了char buf_[256]一些东西.好吧,就像比尔盖茨着名的评论"256KB的记忆应该对任何人都足够",我的错误在低端足以引起我的注意.另一方面,我该怎么办?char buf_[1024*64]?极端,但你明白了.没有完美的幻数.你要么让自己暴露在更多的崩溃中,要么浪费你的记忆.

  2. 我写sprintf了一个字符串,但发送了一个浮点数.一直这样做.好吧,不是所有的时间.对于每100个电话sprintf,我可能会这样做一次或两次.对于生产代码,这是很多.

有了这些流,这些都不会发生.所以我现在使用流,我的代码永远不会崩溃.好吧......无论如何.

有人会说流比sprintf慢.呃,也许吧.为了争论,我甚至会赞同它.虽然没关系.我在实时股票市场服务器上工作,这些服务器每天定期处理300万条消息.而且我从来没有对流的速度有任何问题.也许它有点慢,但我有更大的鱼要炸.