繁体   English   中英

移动和前进案例使用

[英]Move and Forward cases use

我按照本教程学习了C ++ 11中的移动语义和右值引用。 在某个时候,他通过移动构造函数中的std::move实现了这两个类,

我们将临时变量传递给move构造函数,它在新范围内具有新的生命。 在右值表达式被求值的上下文中,临时对象实际上已经结束并完成。 但是在我们的构造函数中,对象有一个名称; 它在我们整个工作过程中都将保持活力。 换句话说,我们可能在函数中不止一次使用变量,并且临时对象具有定义的位置,该位置对于整个函数而言确实存在。 它是术语定位器值的真正意义上的左值

class MetaData
{
public:
    MetaData(int size, const string& name)
        : _name(name)
        , _size(size)
    {}

    MetaData(const MetaData& other)
        : _name(other._name)
        , _size(other._size)
    {
        cout << "MetaData -- Copy Constructor" << endl;
    }

    MetaData(MetaData&& other)
        : _name(move(other._name))
        , _size(other._size)
    {
        cout << "MetaData -- Move Constructor" << endl;
    }

  ~MetaData()
  {
    _name.clear();
  }

    string getName() const { return _name; }
    int getSize() const { return _size; }

private:
    string _name;
    int _size;
};

class ArrayWrapper
{
public:
    ArrayWrapper()
        : _p_vals(new int[64])
        , _metadata(64, "ArrayWrapper")
    {}

    ArrayWrapper(int n)
        : _p_vals(new int[n])
        , _metadata(n, "ArrayWrapper")
    {}

    ArrayWrapper(ArrayWrapper&& other)
        : _p_vals(other._p_vals)
        , _metadata(move(other._metadata))
    {
        cout << "ArrayWrapper -- Move Constructor" << endl;
        other._p_vals = nullptr;
    }

    ArrayWrapper(const ArrayWrapper& other)
        : _p_vals(new int[other._metadata.getSize()])
        , _metadata(other._metadata)
    {
        cout << "ArrayWrapper -- Copy Constructor" << endl;
        for (int i = 0; i < _metadata.getSize(); ++i)
            _p_vals[i] = other._p_vals[i];
    }

    ~ArrayWrapper()
    {
        delete[] _p_vals;
    }

    int* getVals() const { return _p_vals; }
    MetaData getMeta() const { return _metadata; }

private:
    int* _p_vals;
    MetaData _metadata;
};

在ArrayWrapper移动构造函数中,我尝试使用std::forward<MetaData>更改std::move ,代码显示,如果我调用ArrayWrapper移动构造函数,则将调用MetaData移动构造函数,如带有std::move的示例。

当然,如果我不使用std::movestd::forward ,则将调用MetaData复制构造函数。

问题是,在这种情况下,使用std::movestd::forward有区别吗? 为什么要使用一个而不是另一个?

std :: move和std :: forward之间有什么区别? 为什么要使用一个而不是另一个?

是的, std::move返回其参数的右值引用,而std::forward只是转发保留其值类别的参数。

当您明确希望将某物转换为右值时,请使用move 当您不知道所拥有的内容(可以是左值或右值)并且想要将其完美转发(保留其左值或右值)时,请使用forward 我是否可以/通常总是使用std :: forward而不是std :: move? 是您可能对此感兴趣的问题。

在下面的代码段中, bar会准确地获取foo的调用者所传递的内容,包括保留的值类别:

template <class T>
void foo(T&& t) {
    bar(std::forward<T>(t));
}

不要让T&&在这里骗你t不是右值引用 当它出现在类型推断上下文中时, T&&具有特殊含义。 实例化fooT取决于传递的参数是左值还是右值。 如果它是类型U的左值,则将T推导为U& 如果是右值,则将T推导为U 有关详细信息,请参见这篇出色的文章 您需要了解值类别参考崩溃,才能更好地理解这方面的内容。

相关的std::forwardstd::move声明是:

template< class T >
T&& forward( typename std::remove_reference<T>::type& t );

template< class T >
typename std::remove_reference<T>::type&& move( T&& t );

对于前者:

std::forward<MetaData>(other._metadata);

std::forward<MetaData>返回MetaData&&

对于后者:

 std::move(other._metadata);
 //argument derived as lvalue reference due to forwarding reference
 std::move<MetaData&>(other._name);

std::move<MetaData&>返回typename std::remove_reference<MetaData&>::type&& ,即MetaData&&

因此,对于您的示例,这两种形式是相同的。 但是,这里std::move是正确的选择,因为它表明了我们无条件移动参数的意图。 std::forward 用于无条件移动,但其目的是完善其参数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM