我应该移动 std::exchange ed 成员吗?



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。

不,这里不需要使用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 更改了复制省略规则,但这是不同的

从这里你可以看到 prvalue 是:

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

prvalues的属性(作为rvalues的子集(是(强调我的(:

右值

可用于初始化右值引用,在这种情况下 右值标识的对象的生存期延长至 引用的范围结束。

当用作函数参数时,当 函数可用,一个采用右值引用参数和 其他取左值引用 const 参数,右值绑定到 右值引用重载(因此,如果复制和移动 构造函数可用,右值参数调用移动 构造函数,同样使用复制和移动赋值运算符(。

最新更新