c++ - 标准是否要求流构造函数不访问流缓冲区?

标签 c++ c++11 language-lawyer

This (相当老的)关于 iostreams 和 streambuf 的文章认为,以下代码是可以的:

class DerivedStreamBuf : public std::streambuf {
  // ...
};

class DerivedOutputStream : public std::ostream {
  public:
    DerivedOutputStream():
      std::ios(0), std::ostream(&dsb) {}        //1
    // ...
  private:
    DerivedStreamBuf dsb;
    // ...
};
这可能是有问题的,因为当 ostream构造dsb尚未初始化,因此 UB 可能是效果。对于析构函数,它可能是相反的:dsb已经被破坏,可以在 ostream 的析构函数中使用.
然而,文章认为,“C++ 标准要求没有父类的构造函数或析构函数(ios、istream 或 ostream)访问流缓冲区”。
虽然析构函数的情况很简单,例如对于 ~ostream :

virtual ~basic_ostream(); Remarks: Does not perform any operations on rdbuf().


constructor 不太清楚:

explicit basic_ostream(basic_streambuf<charT, traits>* sb); Effects: Initializes the base class subobject with basic_­ios<charT, traits>​::​init(sb) ([basic.ios.cons]).


这是否意味着这是唯一可能的效果,这个标准公式是否不允许其他效果,这些是 std::ostream 的实现细节并且可能访问未初始化的 dsb ?
我的问题:该标准是否保证上述代码是可移植的,即适用于 std::ostream 的所有符合标准的实现?

最佳答案

Does that standard guarantees, that the above code is portable, i.e. works for all standard-compliant implementations of std::ostream?


是的。
在调用 std::ostream(&dsb)dsb DerivedOutputStream 的成员已分配但未初始化。意思是,我们可以通过我们可能还没有读取它的(未初始化的)值来获取它的地址。
如问题中所链接,[ostream.cons]指定 std::basic_ostream 的构造函数,特别是在您的示例中选择的是 [ostream.cons]/1

explicit basic_ostream(basic_streambuf<charT, traits>* sb);

Effects: Initializes the base class subobject with basic_­ios<charT, traits>​::​init(sb) ([basic.ios.cons]).

Postconditions: rdbuf() == sb.


[tab:basic.ios.cons]描述调用 void init(basic_streambuf<charT, traits>* sb) 的效果,特别是上面构造函数中描述的后置条件:
rdbuf() == sb

其余的不执行对 sb 的底层缓冲区的读取访问。点。
现在,rdbuf()只是一个指针,所以这意味着 sb按值传递给 init 的指针(即指针)将用于初始化 rdbuf() .但是,读取 sb 的底层缓冲区没有副作用。指向,此时。

[...] not allow for other effects, ...?


实际上,特别是 void init(basic_streambuf<charT, traits>*) 的实现功能需要尊重而不是扩展 [tab:basic.ios.cons] 的明确规定的效果.

This (pretty old) article ...


请注意,[ostream.cons] 的状态自 C++ 时代以来基本没有变化;我们可以例如看看[lib.input.output]来自 the September 1994 C++ Working Paper

27.2.4.1.1 basic_ostream constructor [lib.basic.ostream.sb.cons]

basic_ostream(basic_streambuf<charT,baggage>* sb);

1 Constructs an object of class basic_ostream, assigning initial values to the base class by calling basic_ios<charT,baggage>::init(sb).



27.1.3.1.34 basic_ios::init [lib.basic.ios::init]

void init(basic_streambuf<charT,baggage>* sb_arg);

1 The postconditions of this function are indicated in Table 8:

                      Table 8--init effects

               +----------------------------------+
               |Element            Value          |
               +----------------------------------+
               |sb        sb_arg                  |
               |tiestr    a null pointer          |
               |state     goodbit  if  sb_arg  is |
               |          not   a  null  pointer, |
               |          otherwise badbit.       |
               |except    goodbit                 |
               |fmtfl     skipws | dec            |
               |wide      zero                    |
               |prec      6                       |
               |fillch    the space character     |
               |loc       new   locale(),   which |
               |          means the default value |
               |          is the  current  global |
               |          locale;9)               |
               |iarray    a null pointer          |
               |parray    a null pointer          |
               +----------------------------------+

通过 init() 描述相同的委托(delegate)调用具有明确的效果。

关于c++ - 标准是否要求流构造函数不访问流缓冲区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64276788/

相关文章:

c++ - 我如何在 C++11 中解决 SICP 2.4

java - 将多继承 C++ 代码移植到 Java

c++ - 如何按类型生成指针 vector ?

python - =+ Python 运算符在语法上是正确的

c++ - 函数在 C++17 中变成 noexcept?

c++ - C++ 11 多线程中 lock_guard 的意外行为

c++ - 树莓派上的 tensorflow lite 量化 ssd 对象检测

c++ - 标准库方法的成员函数指针问题

c++ - C++11 中删除的成员函数的确切语义是什么?

c++ - 为什么 const vector<const pair<...>> 给出 'cannot be overloaded' 错误?