【问题标题】:Should I move the std::exchange ed members?我应该移动 std::exchange ed 成员吗?
【发布时间】:2019-10-17 14:09:29
【问题描述】:

std::exchange 可用于实现移动构造函数。这是来自 cppreference.com https://en.cppreference.com/w/cpp/utility/exchange#Notes 的示例。

但是,std::exchange 的可能实现如下所示:

template<class T, class U = T>
T exchange(T& obj, U&& new_value)
{
    T old_value = std::move(obj);
    obj = std::forward<U>(new_value);
    return old_value;          // can be copy (until C++17) or a move (C++17), right?
}

现在我的情况:

#include <string>
#include <utility>

struct MyClass
{
    std::string m_str;
    // some other non-primitive members of the class

    MyClass(MyClass&& other) : m_str{ std::exchange(other.m_str, {}) } // enough?
        // or
        // : m_str{ std::move(std::exchange(other.m_str, {})) }
        //          ^^^^^^^^^^    do i need to move?                          
    {}

    MyClass& operator=(MyClass&& other)
    {
        this->m_str = std::exchange(other.m_str, {}); // enough?
        // or 
        // this->m_str = std::move( std::exchange(other.m_str, {}) );
        //               ^^^^^^^^^^    do I need to move?   
        return *this;
    }
};

正如我对代码的评论,有机会按行移动或复制

m_str{ std::exchange(other.m_str, {}) }
this->m_str = std::exchange(other.m_str, nullptr);

因此,

  • 我是否应该明确地为他们使用std::move,这样我才能确定 成员是否已 100% 移动到 other 对象?
  • 如果,使用std::exchange 会更冗长吗? 场景?

我正在使用带有编译器标志 C++14 的 Visual Studio 2017。

【问题讨论】:

    标签: c++ c++14 move-constructor


    【解决方案1】:

    不,这里不需要使用std::move。经验法则是 - 如果某些返回值未分配给变量,它将被移动。

    template<class T, class U = T>
    T exchange(T& obj, U&& new_value)
    {
        T old_value = std::move(obj);
        obj = std::forward<U>(new_value);
        return old_value;          // will be moved if move constructor defined
        // or even copy will be elided and will be no constructor call
    }
    

    与你所说的相反,这里的举动是有保证的。 C++17 更改了复制省略规则,但这是不同的

    here可以看出prvalue是:

    函数调用或重载的运算符表达式,其返回类型 是非引用的,比如str.substr(1, 2), str1 + str2, or it++

    纯右值的属性(作为右值的子集)是(强调我的):

    右值可用于初始化右值引用,在这种情况下 由右值标识的对象的生命周期延长到 参考范围结束。

    当用作函数参数并且当 函数可用,一个采用右值参考参数和 其他将左值引用到 const 参数,右值绑定到 右值引用重载(因此,如果复制和移动 构造函数可用,右值参数调用移动 构造函数,以及复制和移动赋值运算符)。

    【讨论】:

    • 也就是说,上面的qestion可以被封装成这样:这个this-&gt;m_str = std::exchange(other.m_str, {});可以解释为some_var = some_func()。是否保证始终是一个 move ,即使它是一个赋值操作(C++14 起)?
    • 从 C++11 开始就可以保证,因为它是从右值分配的
    • 谢谢...看起来很有希望。不过,我会等两天,看看其他人是否对这个问题有任何意见。同时,如果您可以在答案中添加相关引用,那就太好了。
    猜你喜欢
    • 2012-06-05
    • 2013-08-08
    • 1970-01-01
    • 2012-06-12
    • 2011-09-09
    • 2015-11-24
    • 1970-01-01
    • 2012-01-05
    • 2010-12-12
    相关资源
    最近更新 更多