c++ - move 和转发案例使用

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

我关注了this tutorial开始理解 C++11 中的 move 语义和右值引用。 在某些时候,他用 std::move 实现了这两个类。在 move 构造函数中解释

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 move 构造函数中,我尝试更改 std::movestd::forward<MetaData>并且代码显示,如果我调用 ArrayWrapper move 构造函数,这将调用 MetaData move 构造函数,就像带有 std::move 的示例一样.

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

问题是,在这种情况下,使用 std::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 只是转发保留其值类别的参数。

当您明确想要将某些内容转换为右值时,请使用move。当您不知道自己拥有什么(可能是左值或右值)并且想完美地将其转发(保留其 l 或 r 值)到某物时,请使用 forwardCan I typically/always use std::forward instead of std::move?是您可能感兴趣的问题。

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

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

不要让 T&& 在这里骗你 - t is not an rvalue reference .当它出现在类型推导上下文中时,T&& 具有特殊含义。当 foo 被实例化时,T 取决于传递的参数是左值还是右值。如果它是 U 类型的左值,则 T 被推导为 U&。如果它是一个右值,则 T 被推导为 U。参见 this excellent article了解详情。您需要了解 value categoriesreference collapsing更好地理解这方面的事情。

关于c++ - move 和转发案例使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32349944/

相关文章:

c++ - Qt html解析没有找到任何标签

c++ - 为可变参数模板添加的新语法实体的名称是什么?

c++ - 在 C++/CLI 中使用 unique_ptr 时出现链接器错误

c++ - 使用构造函数参数实例化类对象和不带参数 C++ 的 * 运算符之间的区别

c++ - 基于 : issue with constness 范围内的自定义迭代器

c++ - 如何让 Qt Creator 在 Mac M1 上使用 Rosetta 和 x86 编译器?

c++ - 使用未排序的时间范围减少表中的查询时间

c++ - 为什么有些程序以未定义的行为执行而其他程序却没有?

c++ - 我可以使用模板而不是宏来创建异常类吗?

java - 变量未在默认构造函数中初始化