从空缓冲区构造`std::ostream`是否有效?

22

请考虑以下内容:

std::ostream out(nullptr);

这合法且明确定义吗?


如果我现在这样做呢:

out << "hello world\n";

这是否合法且定义得清楚?如果是,则可能是某种无操作。


我总是在认为某个功能应该可以工作并且有效时添加一个单元测试。这样,在其他编译器/平台的标准库中构建时,如果出现故障,他们就会知道它已经损坏了。 - paulm
2
@paulm: 我几乎同意你的看法,除了单元测试并不是您依赖于验证定义良好性的东西。 - Lightness Races in Orbit
除非它访问了越界的内存或其他问题,否则我看不出有什么问题?但是再说一遍,单元测试应该在启用app verifier/valgrind等情况下运行。 - paulm
2
@paulm:这是因为您不能依赖未定义的行为具有可靠、可重现或立即可检测的症状。 - Lightness Races in Orbit
1
即使你发现某些行为是标准行为,但你所依赖的那些晦涩行为仍应该包含在测试套件中。像这样的某些行为可能是某个库/编译器实现中的未知错误。 - Tim Seguine
显示剩余8条评论
1个回答

26

是的,实例化该流是合法且被充分定义的。您可以安全地将其与另一个流交换,或在以后的某个时间给它一个新指针(这次是指向现有缓冲区)。输出操作本身确实是不执行操作的。

原因如下:

  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_ios<charT,traits>::init(sb)(27.5.5.2)对基类赋予初始值,构造basic_ostream类的对象。

  4. init(sb)调用的效果是在sb为NULL时设置流的badbit

    [C++11: 27.5.5.2/3]: 后置条件:此函数的后置条件在表128中指示。

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

  • 输出操作 导致与解除引用空指针等价的操作:

    [C++11: 27.7.3.1/2]: 有两组成员函数签名共享相同属性:格式化输出函数(或插入器)和非格式化输出函数。 这两组输出函数通过等效于调用 rdbuf() -> sputc(int_type) 的操作来生成(或插入)输出字符。 它们可以使用其他 public 成员变量除了不能调用 rdbuf() 的任何虚拟成员,除非是 overflow()xsputn()sync()

    只要对于 basic_ostream::sentry 的构造:

    [C++11: 27.7.3.4/3]: 如果,在完成所有准备工作后,os.good()true,则 ok_ == 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 类对象来完成。如果此对象转换为 bool 类型的值时返回 true,则该函数将努力生成请求的输出。 [..]

    …这意味着当已经设置 badbit 时,根本不会进行任何输出操作。

  • 这在C++03中也是一样的。


    1
    +1 酷毙了!很好知道如何通过使用 std::ostream 来有效地创建 /dev/null - πάντα ῥεῖ

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接