返回一个fstream

时间:2014-04-19 23:05:02

标签: c++ fstream move-semantics rvo

我有这个功能:

fstream open_user_file() const
{
    ...
}

但是我的编译器抱怨隐式删除了fstream copy-constructor。鉴于编译器执行RVO,为什么选择复制构造函数而不是移动构造函数?

否则,最好的方法是什么?

2 个答案:

答案 0 :(得分:8)

目前接受的答案是错误的。

当返回具有自动存储的局部变量时,与声明的函数返回类型的类型相同,则会进行两阶段过程:

fstream open_user_file() const
{
    fstream f;

    /*...*/

    return f;
}
  1. 首先执行复制构造函数的选择,就像对象是由右值指定一样。

  2. 如果第一个重载决策失败或未执行,或者所选构造函数的第一个参数的类型不是对象类型的rvalue引用(可能是cv-qualified),则再次执行重载决策,将对象视为左值。

  3. 这意味着如果f移动可构造,那么返回f将是首选(并且可能被省略)。否则f是可复制的,可以完成(并可能被省略)返回f。否则,无法从此函数返回f,并且会导致编译时错误。

    唯一的情况:

    return std::move(f);
    

    应该有帮助的是实施有缺陷的时候。在符合要求的实现中,fstream是可构造的,并且:

    return f;
    

    将是最佳的。如果f不可移动,那么:

    return std::move(f);
    

    在符合要求的实施方面获得了帮助。如果在符合要求的实现中编码,则会产生悲观效应,因为它会抑制RVO。

    gcc 4.8没有实现可移动流(并且流不可复制)。这是你问题的根源。在C ++ 98,C ++ 03和gcc 4.8中,流不能从函数中返回。在C ++ 11中,它们是。

答案 1 :(得分:3)

实现可能会省略由return语句产生的复制操作,即使复制构造函数有副作用。在这种情况下,您可能只需要明确移动。

fstream open_user_file() const
{
    fstream f;

    /*...*/

    return std::move(f);
}
  

当满足某些条件时,允许实现省略类的复制/移动构造   即使为复制/移动操作选择的构造函数和/或对象的析构函数也是如此   有副作用。

...

这就是说复制构造函数必须可访问的地方:

  

当满足复制操作的省略标准 或将满足时,除了源的事实   object是一个函数参数,要复制的对象由左值, 重载决策指定   选择首先执行复制的构造函数 ,就好像该对象是由rvalue指定的一样。如果过载   分辨率失败,或者所选构造函数的第一个参数的类型不是rvalue引用   对象的类型(可能是cv-qualified),再次执行重载决策,将对象视为   左值。 [注意:无论是否复制,都必须执行此两阶段超载 分辨率   发生。它确定在未执行elision时调用的构造函数以及所选的构造函数   即使通话被取消,也必须可以访问。