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?
\n\n该标准是否保证上述代码是可移植的,即适用于所有符合标准的实现
\nstd::ostream?
是的。
\n在调用时,的成员std::ostream(&dsb)已被分配但尚未初始化。这意味着,我们可以通过尚未读取其(未初始化)值来获取其地址。dsbDerivedOutputStream
正如问题中所链接的,[ostream.cons]指定 的构造函数std::basic_ostream,特别是,您示例中选择的构造函数是[ostream.cons]/1
\n\n显式 basic_ostream(basic_streambuf<charT, Traits>* sb);
\n作用:
\nbasic_\xc2\xadios<charT, traits>\xe2\x80\x8b::\xe2\x80\x8binit(sb)用([basic.ios.cons])初始化基类子对象。后置条件:
\nrdbuf() == sb.
[tab:basic.ios.cons]描述了调用 的效果void init(basic_streambuf<charT, traits>* sb),特别是上面构造函数中描述的后置条件:
\n\nRun Code Online (Sandbox Code Playgroud)\nrdbuf() == sb\n
其余部分不执行对指向的底层缓冲区的读取访问sb。
现在,rdbuf()只是一个指针,所以这意味着按值sb传递给 init 的指针(即指针)将用于初始化。但是,此时读取指向的底层缓冲区没有副作用。rdbuf()sb
\n\n[...]不允许其他影响,...?
\n
事实上,该函数的实现尤其需要尊重而不是扩展[tab:basic.ios.cons]void init(basic_streambuf<charT, traits>*)明确指定的效果。
\n\n这篇(相当旧的)文章......
\n
请注意,自 C++ 时代诞生以来,[ostream.cons] 的状态基本上没有变化;例如,我们可以查看1994 年 9 月 C++ 工作论文中的[lib.input.output]
\n\n\n27.2.4.1.1 basic_ostream 构造函数 [lib.basic.ostream.sb.cons]
\nRun Code Online (Sandbox Code Playgroud)\nbasic_ostream(basic_streambuf<charT,baggage>* sb);\n1 构造 basic_ostream 类的对象,通过调用 为基类分配初始值
\nbasic_ios<charT,baggage>::init(sb)。
和
\n\n\n27.1.3.1.34 basic_ios::init [lib.basic.ios::init]
\nRun Code Online (Sandbox Code Playgroud)\nvoid init(basic_streambuf<charT,baggage>* sb_arg);\n1 该函数的后置条件如表 8 所示:
\nRun Code Online (Sandbox Code Playgroud)\nTable 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
init()它们通过具有明确定义效果的调用来描述相同的委托。