为什么`basic_ios :: swap`只进行部分交换?

时间:2011-11-16 06:57:01

标签: c++ c++11 swap

  

C ++ 11 §27.5.4.2/ 21:

     

void swap(basic_ios& rhs);

     

效果:应交换*thisrhs的状态,但rdbuf()将返回与函数调用之前返回的值相同的值,并且rhs.rdbuf()将返回与函数调用之前返回的值相同的值。

这部分交换对于什么有用?

会引起麻烦吗?

2 个答案:

答案 0 :(得分:21)

你可以怪我这个。委员会试图改变(我认为两次),但每次解决方案最终都会破坏。

交换和移动语义在设计完成十年之后被改装到我们的I / O系统上。而且它不是一个完全干净的适合。

请注意,basic_ios::swap受保护的成员函数,并且没有名称空间范围变体。因此,这只能从派生类(通常是istream / ostream)调用。请注意,i/o_stream::swap也受到保护,并且没有名称空间范围变体。他们的规范是调用基类swap,然后交换任何本地数据(例如gcount中的istream)。

最后,在string/filestream级别,您可以获得“普通”swap:公共成员和名称空间范围变体。在此级别,您有一个数据成员string/file bufferrdbuf)和基类。此级别的swap只是交换基础和数据成员。

所有这一切的复杂特征是基类中的rdbuf()实际上是指向派生类streambufbasic_filebufbasic_stringbuf的自引用指针)和 是你不希望基类交换这些自引用指针的原因。

这会使基础swap变得奇怪,但除了派生客户端之外,每个人都受到保护。而派生客户端swap的代码随后看起来很简单。在派生级别,swap被公开,并以公众客户期望的方式行事。

类似的舞蹈用于移动构造和移动分配。由于基类是虚拟基础,因此其构造函数不会被最直接派生的类调用,因此移动构造变得更加复杂。

很有趣。看起来很奇怪。但它最终有效。 ; - )

轻微更正:

Alberto Ganesh Barbati is responsibleswap级保护i/ostream。这是他非常好的电话,我完全错过了我的第一个设计。

答案 1 :(得分:2)

我只有一个推测性答案......

如果作者假设某个流可能使用内部缓冲区(例如char buffer[50]数据成员),则此规定是必要的,因为显然可以交换缓冲区的内容,但它们的地址将保持不变

我不知道是否允许这样做。