如果 iostream 对象不可复制,为什么以下代码是合法的?

If iostream objects are not copyable, why is the following code legal?

本文关键字:代码 对象 iostream 可复制 为什么 如果      更新时间:2023-10-16

我一直在读"C++入门",在第8章中我们讨论了I/O。声明无法复制或分配 I/O 对象。如果是这样,那么为什么下面的代码要编译并运行呢?

std::ifstream get_lines(const std::string &fname, std::vector<std::string> &v)
{
std::ifstream file(fname);
if (!file) {
std::cerr << "Error opening file: " << fname << std::endl;
return file;
}
std::string buf;
while (std::getline(file, buf))
v.push_back(buf);
return file;
}
int main()
{
std::vector<std::string> v;
auto f = get_lines("test.txt", v);
f.close();
return 0;
}

返回不会创建随后用于初始化ffile副本吗?

请参阅此页面。当你说

return file;

file是一个"id-expression"(即它是某个变量的名称(。这些在return下有特殊处理:

自动从局部变量和参数移动

如果表达式是一个(可能是括号(命名变量的 id 表达式......然后重载解析以选择要用于初始化返回值的构造函数...执行两次

  • 首先,好像表达式是右值表达式(因此它可以选择移动构造函数(,...
  • 然后像往常一样执行重载解析,将表达式视为左值(因此它可以选择复制构造函数(。

你不能复制ifstream,这是真的,但你可以移动它。因此,编译器实质上为您插入了一个隐式std::move

return std::move(file);

这允许调用ifstream的移动构造函数,即使复制构造函数被删除也是如此。"移动"意味着istream"拥有"的任何资源都转移到新对象。移动构造函数将这些资源的所有权从源对象手中夺走(从而对其进行修改(,同时将其提供给新对象。对比复制构造函数,我们通常认为它不应该修改源代码,因此不能剥夺它的所有权。这使得复制构造函数对istream不安全,因为这意味着两个对象试图管理一个外部资源并可能相互混淆。移动构造函数不受协定的约束,使源对象保持不变,因此它可以确保资源仅由一个对象拥有。