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

ead*_*ead 5 c++ language-lawyer c++11

对输入输出流和流缓冲(很老)的文章指出,下面的代码即可:

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

class DerivedOutputStream : public std::ostream {
  public:
    DerivedOutputStream():
      std::ios(0), std::ostream(&dsb) {}        //1
    // ...
  private:
    DerivedStreamBuf dsb;
    // ...
};
Run Code Online (Sandbox Code Playgroud)

这可能有问题,因为何时ostream构造dsb尚未初始化,因此 UB 可能是效果。对于析构函数,它可能是相反的:dsb已经被破坏并且可以在 的析构函数中使用ostream

但是,文章认为,“C++ 标准要求父类构造函数或析构函数(ios、istream 或 ostream)不能访问流缓冲区”。

虽然析构函数的情况很简单,例如~ostream

虚拟 ~basic_ostream(); 备注:不对 rdbuf() 执行任何操作。

构造函数不太清楚:

显式 basic_ostream(basic_streambuf<charT, traits>* sb); 效果:使用 basic_ios<charT, traits>?::?init(sb) ([basic.ios.cons]) 初始化基类子对象。

这是否意味着这是唯一可能的效果,这个标准公式是否不允许其他效果,这些效果是 的实现细节std::ostream并且可能访问 non-initialized dsb

我的问题:该标准是否保证上述代码是可移植的,即适用于所有符合标准的实现std::ostream

dfr*_*fri 2

\n

该标准是否保证上述代码是可移植的,即适用于所有符合标准的实现std::ostream

\n
\n

是的。

\n

在调用时,的成员std::ostream(&dsb)已被分配但尚未初始化。这意味着,我们可以通过尚未读取其(未初始化)值来获取其地址。dsbDerivedOutputStream

\n

正如问题中所链接的,[ostream.cons]指定 的构造函数std::basic_ostream,特别是,您示例中选择的构造函数是[ostream.cons]/1

\n
\n

显式 basic_ostream(basic_streambuf<charT, Traits>* sb);

\n

作用:basic_\xc2\xadios<charT, traits>\xe2\x80\x8b::\xe2\x80\x8binit(sb)用([basic.ios.cons])初始化基类子对象。

\n

后置条件: rdbuf() == sb .

\n
\n

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

\n
\n
rdbuf() == sb\n
Run Code Online (Sandbox Code Playgroud)\n
\n

其余部分不执行对指向的底层缓冲区的读取访问sb

\n

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

\n
\n

[...]不允许其他影响,...?

\n
\n

事实上,该函数的实现尤其需要尊重而不是扩展[tab:basic.ios.cons]void init(basic_streambuf<charT, traits>*)明确指定的效果。

\n
\n
\n

这篇(相当旧的)文章......

\n
\n

请注意,自 C++ 时代诞生以来,[ostream.cons] 的状态基本上没有变化;例如,我们可以查看1994 年 9 月 C++ 工作论文中的[lib.input.output]

\n
\n

27.2.4.1.1 basic_ostream 构造函数 [lib.basic.ostream.sb.cons]

\n
basic_ostream(basic_streambuf<charT,baggage>* sb);\n
Run Code Online (Sandbox Code Playgroud)\n

1 构造 basic_ostream 类的对象,通过调用 为基类分配初始值basic_ios<charT,baggage>::init(sb)

\n
\n

\n
\n

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

\n
void init(basic_streambuf<charT,baggage>* sb_arg);\n
Run Code Online (Sandbox Code Playgroud)\n

1 该函数的后置条件如表 8 所示:

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

init()它们通过具有明确定义效果的调用来描述相同的委托。

\n