为什么iostreams不可复制?

时间:2016-03-17 04:26:04

标签: c++ iostream copy-constructor

possible使用rdbufcopyfmt制作iostream对象的本地副本。这允许格式更改在本地作用域:

std::ostream & operator << ( std::ostream & os, foo const & smth ) {
    cloned_ostream cs( os );
    cs << std::hex << smth.num;
    // os is not switched to hexadecimal, which would be a confusing side-effect
    return os;
}

为什么流类不提供复制构造函数来执行此操作?

是否更改了相关的C ++最佳实践,因为它们被设计为不可复制的?

1 个答案:

答案 0 :(得分:7)

复制和移动是价值语义操作。要定义它们,首先必须确定类的哪些属性为其对象赋予不同的值。这一点最初基本上是为iostreams库所回避,然后C ++ 11采用了与这种拷贝构造函数不兼容的不同方向。

流对象的状态包括两部分:指向具有关联状态的流缓冲区的指针,以及格式化信息。自C ++ 98起,rdbufrdstatecopyfmt会单独公开此信息。

从C ++ 11开始,流类还有一个protected接口,包括一个移动构造函数(和一个名为move的成员),它复制格式但不复制流缓冲区指针。这将提交iostream,将格式化信息专门视为流对象的状态。

如果此时流可以复制,那么它只会copyfmt,而不是其余的。

从值状态中排除rdbuf的选择可能是由于派生类(例如std::fstream)的进一步混乱值语义,它不仅暴露了对流缓冲区的访问,而且还嵌入了拥有它。

std::ifstream f( path + filename ); // Owns, or even "is," a file.
std::istream i = f; // Observes an externally-managed file.

std::istream i2 = i; // OK, copy a shallow reference.
std::ifstream f2 = f; // Error, ifstream is more than a shallow reference.

std::istream i3 = std::move( f ); // Error? Would retain a reference to an rvalue.
std::ifstream f3 = std::move( f ); // OK: full copy including the file buffer.

语义可能会以某种方式保持一致,但对于适度的收益会有很多困惑。