【问题标题】:Is it valid to construct an `std::ostream` from a null buffer?从空缓冲区构造`std::ostream`是否有效?
【发布时间】:2014-10-30 16:30:51
【问题描述】:

考虑以下几点:

std::ostream out(nullptr);

这合法且定义明确吗?


如果我现在这样做呢:

out << "hello world\n";

这是否合法且定义明确?如果是这样,大概是一种无操作?

【问题讨论】:

  • 如果我认为这样的事情应该有效并且似乎有效,我总是添加一个单元测试。这样,如果有人为另一个编译器/平台 stdlib 构建,那么他们就知道它坏了。
  • @paulm:我几乎同意,除了单元测试不是你应该用来验证定义良好的东西。
  • 除非它访问内存越界或我没有看到问题?但是单元测试应该在启用应用程序验证器/valgrind 等的情况下运行
  • @paulm:这是因为您不能依赖 UB 来获得可靠、可重复或可立即检测到的症状。
  • 您所依赖的晦涩行为应该始终在测试套件中,即使您发现它在标准中也是如此。像这样的某些事情可能是某些库/编译器实现中的未知错误。

标签: c++ c++11 std iostream


【解决方案1】:

是的,实例化该流是合法且定义明确的。您可以安全地将其与另一个流交换,或者稍后给它一个新指针(这次指向现有缓冲区)。输出操作本身确实是空操作。

原因如下:

  1. 构造没有非空前置条件,只有这个后置条件:

    [C++11: 27.7.3.2/2]: 后置条件:rdbuf() == sb

  2. 有趣的是,它明确指出不应在构造函数中对sb 执行任何操作:

    [C++11: 27.7.3.2/4]: 备注:不对rdbuf()进行任何操作。

  3. 但也要注意:

    [C++11: 27.7.3.2/1]: 效果:构造basic_ostream 类的对象,通过调用basic_ios&lt;charT,traits&gt;::init(sb) (27.5.5.2) 为基类分配初始值。

  4. init(sb) 调用具有当sb 为NULL 时在流上设置badbit 的效果:

    [C++11: 27.5.5.2/3]:后置条件:该函数的后置条件如表128所示。

    [C++11: Table 128]: [..] rdstate(): goodbit 如果sb 不是空指针,否则 badbit[..]

  5. 输出操作导致相当于取消引用空指针的操作:

    [C++11: 27.7.3.1/2]: 两组成员函数签名共享共同的属性:格式化输出函数(或插入器)和未格式化输出函数。 两组输出函数通过相当于调用rdbuf()-&gt;sputc(int_type)的动作生成(或插入)输出字符。它们可以使用basic_ostream的其他公共成员,但不能调用@987654342的任何虚拟成员@ 除了overflow()xsputn()sync()

    除了它从来没有走到这一步,因为 basic_ostream::sentry 构造:

    [C++11: 27.7.3.4/3]:如果任何准备完成后os.good()trueok_ == true否则,ok_ == false

    对于explicit operator basic_ostream::sentry::bool() const;

    [C++11: 27.7.3.4/5]: 效果:返回ok_

    和:

    [C++11: 27.7.3.7/1]: 每个未格式化的输出函数通过构造sentry 类的对象开始执行。如果此对象返回true,同时转换为bool 类型的值,该函数将努力生成请求的输出。 [..]

    ...这意味着当badbit 已经设置时,根本不会发生任何输出操作。

This was also the case in C++03.

【讨论】:

  • +1 很酷的东西!很高兴知道,如何通过使用std::ostream 有效地制作/dev/null
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-23
  • 2012-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多