c++ - 标准是否要求流构造函数不访问流缓冲区?
问题描述
这篇关于 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
:
虚拟〜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
?
解决方案
该标准是否保证上述代码是可移植的,即适用于所有符合标准的实现
std::ostream
?
是的。
在调用std::ostream(&dsb)
时,dsb
成员DerivedOutputStream
已分配但未初始化。意思是,我们可以通过我们可能还没有读取它的(未初始化的)值来获取它的地址。
如问题中所链接,[ostream.cons]指定 的构造函数std::basic_ostream
,特别是在您的示例中选择的构造函数是[ostream.cons]/1
显式 basic_ostream(basic_streambuf<charT, traits>* sb);
效果:
basic_ios<charT, traits>::init(sb)
使用([basic.ios.cons])初始化基类子对象。后置条件:
rdbuf() == sb
.
[tab:basic.ios.cons]描述了调用的效果,void init(basic_streambuf<charT, traits>* sb)
特别是上面构造函数中描述的后置条件:
rdbuf() == sb
其余部分不执行对指向的底层缓冲区的读取访问sb
。
现在,rdbuf()
只是一个指针,所以这意味着按值sb
传递给 init的指针(即指针)将用于初始化。但是,此时读取指向的底层缓冲区没有副作用。rdbuf()
sb
[...] 不允许其他效果,...?
实际上,特别是void init(basic_streambuf<charT, traits>*)
函数的实现需要尊重而不是扩展[tab:basic.ios.cons]的明确指定的效果。
这篇(相当古老的)文章...
请注意,[ostream.cons] 的状态自 C++ 时代以来基本没有变化;例如,我们可以看看1994年9 月 C++ 工作论文中的[lib.input.output]
27.2.4.1.1 basic_ostream 构造函数 [lib.basic.ostream.sb.cons]
basic_ostream(basic_streambuf<charT,baggage>* sb);
1 构造类 basic_ostream 的对象,通过调用为基类分配初始值
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 该函数的后置条件如表 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()
它通过具有明确定义的效果的调用来描述相同的委托。
推荐阅读
- amazon-web-services - AWS:Elastic Beanstalk 和 Auto Scaling(内存不足时)
- r - 为什么 tsCV 适合与 ets/auto.arima 等模型选择算法一起使用?
- c# - 使用 C# 插入/更新 SQL 的自定义函数
- angularjs - Angular 上下文中的 AngularJS 代码:ng-if 在 DIV 上,意外结果
- wpf - 在 WPF 窗口中显示 MessageBox,而不是在 WPF 中的屏幕中心
- c# - 尝试对简单计算运行单元测试时 SQLite 出错
- c++ - 我应该总是声明比我的字符串大的 char 数组吗?
- c# - 如何在 ASP.NET MVC 中使用实体框架显示三个表数据?
- button - Bootstrap 4.1 按钮之间的空格
- r - eval(expr,envir,enclos)中的错误:为什么将字符串视为函数