【问题标题】:rvalue reference and setup functions右值引用和设置函数
【发布时间】:2015-12-23 11:30:49
【问题描述】:

我想在我的 main() 函数中创建类实例时使用便利函数以使事情更清晰。

这是一个最小的例子:

class MyClass
{
    public:
            MyClass() : value{ -1 }, str{ "hello" } {}
            MyClass( const MyClass &&other )
            {
                    value = move( other.value );
                    str = move( other.str );
                    file = move( other.file ); //Use of deleted function...
            }

            void open()
            {
                    file.open( "myfile" );
            }

    private:
            MyClass( const MyClass & ) = delete;
            MyClass operator=( const MyClass & ) = delete;
            MyClass &operator=( const MyClass && ) = delete;

            ofstream file;
            int value;
            string str;
};

inline MyClass setup_myclass()
{
    MyClass ret;
    ret.open();

    return ret;
}

int main( int argc, char **argv )
{
    MyClass &&mc = setup_myclass();

    return 0;
}

问题是当我的类包含 fstream 或线程之类的东西时,它们的移动构造函数已被删除。

我正在使用 g++ 5.1.1 和 arm-linux-g++ 5.2.0(raspberrypi,buildroot)进行编译。

当我的成员删除了移动构造函数时,我的移动构造函数应该是什么样子?

如何更改我的代码以具有相同的干净主要功能?

【问题讨论】:

  • std::ofstream 有一个移动构造函数。 it is the copy constructor that is deleted
  • 内容有误。 std::ofstream 和 std::thread 都有移动构造函数。为什么你认为你在那里有问题?提供编译器消息。
  • MyClass( const MyClass &&other )改成MyClass( MyClass &&other )

标签: c++ c++11 move-semantics


【解决方案1】:

这里有两个问题。首先,你的移动构造函数有错误的签名:

MyClass( const MyClass &&other )

您不能从const 右值移动。你的意思是:

MyClass( MyClass &&other )

不仅如此,你的真正意思是:

MyClass( MyClass &&other ) = default;

Rule of Zero。您的所有成员都有移动构造函数(std::threadstd::ofstream 也有!),所以只需使用它们。同样,这个:

MyClass &operator=( const MyClass && ) = delete;

应该是 public 并且看起来像:

MyClass &operator=( MyClass && ) = default;

为什么要启用移动构造函数而不是delete 移动赋值?

其次,这很糟糕:

MyClass &&mc = setup_myclass();

您只是引用了一个在行尾被销毁的临时文件。你现在有一个悬空的参考。你想做的只是:

MyClass mc = setup_myclass();

感谢 RVO,这里实际上不会调用移动。 setup_myclass() 中的临时对象实际上将在 mc 中就地构建。

【讨论】:

  • “你只是引用了一个在行尾被销毁的临时文件。”,不将临时文件直接绑定到右值引用会延长生命周期那个临时的?
  • @PiotrSkotnicki 不。 “在函数 return 语句 (6.6.3) 中绑定到返回值的临时对象的生命周期不会延长;临时对象在 return 语句中的完整表达式结束时被销毁。”
  • 这是引用扩展的一个令人讨厌且令人惊讶的(但不是真的)例外。我总是忘记了。
  • @Barry 但您获得了返回值的副本,这是一个受该引用绑定的纯右值,isn't it? 您没有直接从 return 语句绑定到该对象
  • @PiotrSkotnicki 嗯,也许这句话是关于如果返回值类型是一个引用。无论如何,没有理由将mc 作为参考。充其量只是看起来不对。在最坏的情况下,它错误的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-19
  • 1970-01-01
  • 2014-03-29
  • 1970-01-01
  • 1970-01-01
  • 2012-10-07
  • 2017-12-03
相关资源
最近更新 更多