我应该移动 std::exchange ed 成员吗?
Should I move the std::exchange ed members?
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 改变了复制省略规则,但这是不同的
从here可以看出prvalue是:
function call or an overloaded operator expression, whose return type
is non-reference, such as str.substr(1, 2), str1 + str2, or it++
右值的属性(作为右值的子集)是(强调我的):
An rvalue may be used to initialize an rvalue reference, in which case
the lifetime of the object identified by the rvalue is extended until
the scope of the reference ends.
When used as a function argument and when two overloads of the
function are available, one taking rvalue reference parameter and the
other taking lvalue reference to const parameter, an rvalue binds to
the rvalue reference overload (thus, if both copy and move
constructors are available, an rvalue argument invokes the move
constructor, and likewise with copy and move assignment operators).
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 改变了复制省略规则,但这是不同的
从here可以看出prvalue是:
function call or an overloaded operator expression, whose return type is non-reference, such as str.substr(1, 2), str1 + str2, or it++
右值的属性(作为右值的子集)是(强调我的):
An rvalue may be used to initialize an rvalue reference, in which case the lifetime of the object identified by the rvalue is extended until the scope of the reference ends.
When used as a function argument and when two overloads of the function are available, one taking rvalue reference parameter and the other taking lvalue reference to const parameter, an rvalue binds to the rvalue reference overload (thus, if both copy and move constructors are available, an rvalue argument invokes the move constructor, and likewise with copy and move assignment operators).