为什么std::ostream无法移动?

58

显然,流无法复制。可以将流移动。根据27.9.1.11 [ofstream.cons]第4段,可以移动构造一个std :: ofstream(对于std :: ifstream std :: fstream std :: * stringstream 变体也是如此)。例如:

#include <iostream>
#include <fstream>
#include <string>

std::ofstream makeStream(std::string const& name) {
    return std::ofstream(name);
}

int main()
{
    std::ofstream out{ makeStream("example.log") };
}

尝试移动 std::ostream,比如通过一个工厂函数创建一个根据传递的 URN 创建 std::ofstreamstd::ostringstream 或其他流的函数,并不起作用。实际上,std::ostream(确切地说是类模板 std::basic_ostream)根据 27.7.3.1 [ostream] 有一个受保护的移动构造函数。

为什么不能移动 std::ostream 自身?


你会把 std::ostream 移动到哪里?除非我误解了你的意思,否则你需要创建派生类的实例,如果你不知道派生类在编译时是什么,移动该如何进行? - user743382
@hvd:我可以创建一个类型为std::ostream的对象,例如使用std::ostream out(new std::filebuf("example.log"));(请注意,此代码需要一些工作来避免内存泄漏,但可以通过注册适当的回调函数来完成)。 - Dietmar Kühl
你在问题中提到了 ofstream/ostringstream,而不是直接使用 ostream。它们对它们的工作方式会有什么影响? - user743382
根据你的论点,只有final类应该是公开可移动的,但其他类型(例如std::stringstd::vector<T>)显然不是这种情况,尽管最好不要从这些类派生。我怀疑意外切割流的潜在风险可能是原因,虽然Howard发布的链接指出了其他问题。 - Dietmar Kühl
哦,我并不是说它应该是公开可移动的,也不是说它不应该是。我是说,即使它是公开可移动的,根据你在问题中提供的信息,它对你也没有用。 - user743382
显示剩余2条评论
1个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
60

原本它们是可移动的。这被我视为设计缺陷,并由Alberto Ganesh Barbati发现:

http://cplusplus.github.io/LWG/lwg-defects.html#911

该问题展示了一些ostream被移动和/或交换的例子,结果出人意料,而不是预期的。因此,我确信这些类型不应通过此问题公开地移动和交换。


4
嗯,我明白问题所在,但我不确定我同意的解决方案是使它们不可移动。相反,应该改变实现方式,以便代码具有预期的行为(通过删除流的实际类型,我会假设)。Dietmar提出了一个令人信服的使用案例,说明流应该是可移动的(我以前也遇到过同样的问题)。 - Konrad Rudolph
1
@KonradRudolph:问题在于自定义流缓冲区通常嵌入到实际对象中而不是在堆上分配。强制std::ostream可移动将强制要求流缓冲区被不同地分配,这是不可行的(对于标准流类可能是可行的,但对于现有的用户定义流则不是)。我猜,返回未知类型的流的用例最好以不同的方式解决。 - Dietmar Kühl
@HowardHinnant 派生的 ofstream 仍然可以移动,对吗? - Koushik Shetty
1
@Koushik:是的,ofstream(和其他“具体”流类型)都是可移动和交换的。 - Howard Hinnant
我正在尝试理解这个逻辑。除了链接中显示的不一致之外,还可以说 ostreams 不应该是可移动的,因为否则就可以从 std::cout 移动或交换了吗? - alfC
1
那是一个不错的副作用,但它从未是一项激励因素。人们可以对std::cout进行相当破坏性的操作。例如,std::cout.rdbuf(nullptr);仍然是完全合法的(但不可取)。 - Howard Hinnant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,