简体   繁体   English

移动和前进案例使用

[英]Move and Forward cases use

I followed this tutorial to start to understand the move semantics and rvalue references in C++11. 我按照本教程学习了C ++ 11中的移动语义和右值引用。 At some point, he implements these two classes with the std::move in the move constructors explaining that 在某个时候,他通过移动构造函数中的std::move实现了这两个类,

we pass the temporary to a move constructor, and it takes on new life in the new scope. 我们将临时变量传递给move构造函数,它在新范围内具有新的生命。 In the context where the rvalue expression was evaluated, the temporary object really is over and done with. 在右值表达式被求值的上下文中,临时对象实际上已经结束并完成。 But in our constructor, the object has a name; 但是在我们的构造函数中,对象有一个名称; it will be alive for the entire duration of our function. 它在我们整个工作过程中都将保持活力。 In other words, we might use the variable other more than once in the function, and the temporary object has a defined location that truly persists for the entire function. 换句话说,我们可能在函数中不止一次使用变量,并且临时对象具有定义的位置,该位置对于整个函数而言确实存在。 It's an lvalue in the true sense of the term locator value 它是术语定位器值的真正意义上的左值

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;
};

In the ArrayWrapper move constructor I tried to change std::move with std::forward<MetaData> and the code shows that if I call the ArrayWrapper move constructor this will call the MetaData move constructor, like the example with the std::move . 在ArrayWrapper移动构造函数中,我尝试使用std::forward<MetaData>更改std::move ,代码显示,如果我调用ArrayWrapper移动构造函数,则将调用MetaData移动构造函数,如带有std::move的示例。

Of course if I don't use either std::move or std::forward the MetaData copy costructor will be called. 当然,如果我不使用std::movestd::forward ,则将调用MetaData复制构造函数。

The question is, in this case, is there a difference between using std::move and std::forward ? 问题是,在这种情况下,使用std::movestd::forward有区别吗? Why should I use one instead of the other? 为什么要使用一个而不是另一个?

is there a difference between using std::move and std::forward? std :: move和std :: forward之间有什么区别? Why should I use one instead of the other? 为什么要使用一个而不是另一个?

Yes, std::move returns an rvalue reference of its parameter, while std::forward just forwards the parameter preserving its value category. 是的, std::move返回其参数的右值引用,而std::forward只是转发保留其值类别的参数。

Use move when you clearly want to convert something to an rvalue. 当您明确希望将某物转换为右值时,请使用move Use forward when you don't know what you've (may be an lvalue or an rvalue) and want to perfectly forward it (preserving its l or r valueness) to something. 当您不知道所拥有的内容(可以是左值或右值)并且想要将其完美转发(保留其左值或右值)时,请使用forward Can I typically/always use std::forward instead of std::move? 我是否可以/通常总是使用std :: forward而不是std :: move? is a question you might be interested in here. 是您可能对此感兴趣的问题。

In the below snippet, bar would get exactly what the caller of foo had passed, including its value category preserved: 在下面的代码段中, bar会准确地获取foo的调用者所传递的内容,包括保留的值类别:

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

Don't let T&& fool you here - t is not an rvalue reference . 不要让T&&在这里骗你t不是右值引用 When it appears in a type-deducing context, T&& acquires a special meaning. 当它出现在类型推断上下文中时, T&&具有特殊含义。 When foo is instantiated, T depends on whether the argument passed is an lvalue or an rvalue. 实例化fooT取决于传递的参数是左值还是右值。 If it's an lvalue of type U , T is deduced to U& . 如果它是类型U的左值,则将T推导为U& If it's an rvalue, T is deduced to U . 如果是右值,则将T推导为U See this excellent article for details. 有关详细信息,请参见这篇出色的文章 You need to understand about value categories and reference collapsing to understand things better in this front. 您需要了解值类别参考崩溃,才能更好地理解这方面的内容。

The relevant std::forward and std::move declarations are: 相关的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 );

For the former: 对于前者:

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

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

For the latter: 对于后者:

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

std::move<MetaData&> returns typename std::remove_reference<MetaData&>::type&& , which is MetaData&& . std::move<MetaData&>返回typename std::remove_reference<MetaData&>::type&& ,即MetaData&&

So the two forms are identical for your example. 因此,对于您的示例,这两种形式是相同的。 However, std::move is the right choice here, as it shows our intent to unconditionally move the argument. 但是,这里std::move是正确的选择,因为它表明了我们无条件移动参数的意图。 std::forward can be used to unconditionally move, but the purpose of it is to perfect-forward its argument. std::forward 用于无条件移动,但其目的是完善其参数。

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

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