4

我有这个功能:

fstream open_user_file() const
{
    ...
}

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

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

4

2 回答 2

10

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

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

fstream open_user_file() const
{
    fstream f;

    /*...*/

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

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

这意味着 iff是 move 可构造的,这将是首选(并且可能省略)返回f。否则 iff是可复制构造的,将在返回时完成(并且可能省略)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 中它们是。

于 2014-04-21T03:44:50.350 回答
3

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

fstream open_user_file() const
{
    fstream f;

    /*...*/

    return std::move(f);
}

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

...

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

当满足或将满足复制操作的省略标准时,除了源对象是函数参数的事实,并且要复制的对象由左值指定时,选择复制的构造函数的重载决策是首先执行好像对象是由右值指定的。如果重载决议失败,或者如果所选构造函数的第一个参数的类型不是对对象类型的右值引用(可能是 cv 限定的),则再次执行重载决议,将对象视为左值。[注:此两级过载无论是否会发生复制省略,都必须执行解析。它确定如果不执行省略则要调用的构造函数,并且即使调用被省略,所选构造函数也必须是可访问的。

于 2014-04-19T23:18:14.647 回答