移动和转发案例使用 [英] Move and Forward cases use

查看:266
本文介绍了移动和转发案例使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遵循本教程开始理解C ++ 11中的移动语义和右值引用。
在某些时候,他在move构造函数中用 std :: move 来实现这两个类,解释

I followed this tutorial to start to understand the move semantics and rvalue references in C++11. At some point, he implements these two classes with the std::move in the move constructors explaining that


我们将临时值传递给移动构造函数,它在新作用域中占用新的生命
。在对右值表达式
求值的上下文中,临时对象真的结束了。但在
我们的构造函数,对象有一个名称;它将为我们的函数的
的整个持续时间活着。换句话说,我们可能在函数中使用
变量多于一次,临时
对象具有一个定义的位置,对于整个
函数来说,它是真正存在的。这是真正意义上的术语locator值的左值

we pass the temporary to a move constructor, and it takes on new life in the new scope. 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;
};

在ArrayWrapper移动构造函数中,我试图更改 std :: move std :: forward< MetaData> ,代码显示如果我调用ArrayWrapper移动构造函数,这将调用MetaData移动构造函数, std :: move

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.

当然,如果我不使用 std :: move std :: forward 将调用MetaData副本构造函数。

Of course if I don't use either std::move or std::forward the MetaData copy costructor will be called.

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

The question is, in this case, is there a difference between using std::move and std::forward? Why should I use one instead of the other?

推荐答案


:move和std :: forward?为什么要使用一个而不是另一个?

is there a difference between using std::move and std::forward? Why should I use one instead of the other?

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

Yes, std::move returns an rvalue reference of its parameter, while std::forward just forwards the parameter preserving its value category.

当你明确想要将某个东西转换为右值时,使用 move 。当你不知道你有什么(可能是一个左值或右值),并希望完全转发它(保持其价值或价值)时,使用 forward 我通常可以/总是使用std :: forward而不是std :: move?是您可能感兴趣的问题。

Use move when you clearly want to convert something to an rvalue. 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. Can I typically/always use std::forward instead of std::move? is a question you might be interested in here.

在下面的代码片段中, bar 会得到 foo 已过,包括其值类别保留:

In the below snippet, bar would get exactly what the caller of foo had passed, including its value category preserved:

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

不要让 T& code> fool you here - t 不是有价值的参考 a>。当它出现在类型推导的上下文中时, T&& 获得特殊含义。当 foo 被实例化时, T 取决于传递的参数是左值还是右值。如果它是类型 U 的左值,则 T 被推导为 U& 。如果它是一个右值, T 被推导到 U 。有关详情,请参见这篇精彩文章。您需要了解值类别参考折叠以更好地了解这一面。

Don't let T&& fool you here - t is not an rvalue reference. When it appears in a type-deducing context, T&& acquires a special meaning. When foo is instantiated, T depends on whether the argument passed is an lvalue or an rvalue. If it's an lvalue of type U, T is deduced to U&. If it's an rvalue, T is deduced to U. See this excellent article for details. You need to understand about value categories and reference collapsing to understand things better in this front.

这篇关于移动和转发案例使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆