std::move(3)
π
std::move β the C++ Standard Library glow-up you've been waiting for (a.k.a. std::move(3))
okay so bestie, listen. this is std::move, and it lives in the C++ Standard Library β it's literally the main character of move semantics and you're about to be obsessed. π
π NAME π
std::move β yes, the function is named std::move. iconic, no notes. β¨
πΈ SYNOPSIS πΈ
first things first: it's defined in header <utility> β go include it, bestie, it's not gonna include itself. π«Ά
until C++14:
template< class T >
typename std::remove_reference<T>::type&& move( T&& t ) noexcept;
since C++14: (she got a constexpr glow-up π
β and the return type got the _t treatment)
template< class T >
constexpr std::remove_reference_t<T>&& move( T&& t ) noexcept;
(also, std::move has been hanging around since C++11, just so we're clear on the lore β¨)
So what does she do? std::move is used to indicate that an object t may be "moved from" β i.e., allowing the efficient transfer of resources from t to another object. no cap. π₯
In particular, std::move produces an xvalue expression that identifies its argument t. It is exactly equivalent to a static_cast to an rvalue reference type. that's it. that's the whole function. she's literally one cast in a trench coat and she ate. π
π PARAMETERS π
tβ the object to be moved π¦
π RETURN VALUE π
static_cast<typename std::remove_reference<T>::type&&>(t)
π§ NOTES π§
okay this is the part where it gets good, so pay attention bestie. π
The functions that accept rvalue reference parameters β including move constructors, move assignment operators, and regular member functions such as std::vector::push_back β are selected, by overload resolution, when called with rvalue arguments (either prvalues such as a temporary object, or xvalues such as the one produced by std::move). If the argument identifies a resource-owning object, these overloads have the option, but aren't required, to move any resources held by the argument. like, they can, not they must, iykyk.
For example, a move constructor of a linked list might copy the pointer to the head of the list and store nullptr in the argument instead of allocating and copying individual nodes. efficiency slay. β¨
Names of rvalue reference variables are lvalues and have to be converted to xvalues to be bound to the function overloads that accept rvalue reference parameters β which is why move constructors and move assignment operators typically use std::move. it's giving "you have to announce it out loud or nobody knows it's an rvalue." π
// Simple move constructor
A(A&& arg) : member(std::move(arg.member)) // the expression "arg.member" is lvalue
{}
// Simple move assignment operator
A& operator=(A&& other)
{
member = std::move(other.member);
return *this;
}
One exception is when the type of the function parameter is a forwarding reference (which looks like an rvalue reference to type template parameter), in which case std::forward is used instead. different tool, different vibe. π¦
β οΈ Unless otherwise specified, all standard library objects that have been moved from are placed in a "valid but unspecified state" β meaning the object's class invariants hold (so functions without preconditions, such as the assignment operator, can be safely used on the object after it was moved from). valid but unspecified is basically "she's alive but don't ask her questions." π
std::vector<std::string> v;
std::string str = "example";
v.push_back(std::move(str)); // str is now valid but unspecified
str.back(); // undefined behavior if size() == 0: back() has a precondition !empty()
if (!str.empty())
str.back(); // OK, empty() has no precondition and back() precondition is met
str.clear(); // OK, clear() has no preconditions
Also, the standard library functions called with xvalue arguments may assume the argument is the only reference to the object; if it was constructed from an lvalue with std::move, no aliasing checks are made. π However, self-move-assignment of standard library types is guaranteed to place the object in a valid (but usually unspecified) state β so it's not UB, it's just... vibes. π
std::vector<int> v = {2, 3, 3};
v = std::move(v); // the value of v is unspecified
π₯ EXAMPLE π₯
// Run this code
#include <iomanip>
#include <iostream>
#include <string>
#include <utility>
#include <vector>
int main()
{
std::string str = "Salut";
std::vector<std::string> v;
// uses the push_back(const T&) overload, which means
// we'll incur the cost of copying str
v.push_back(str);
std::cout << "After copy, str is " << std::quoted(str) << '\n';
// uses the rvalue reference push_back(T&&) overload,
// which means no strings will be copied; instead, the contents
// of str will be moved into the vector. This is less
// expensive, but also means str might now be empty.
v.push_back(std::move(str));
std::cout << "After move, str is " << std::quoted(str) << '\n';
std::cout << "The contents of the vector are {" << std::quoted(v[0])
<< ", " << std::quoted(v[1]) << "}\n";
}
β Possible output β
After copy, str is "Salut"
After move, str is ""
The contents of the vector are {"Salut", "Salut"}
see how str got emptied after the move?? that's the whole point, bestie. she gave her contents to the vector and now she's just a shell. valid but unspecified. π«Ά
π SEE ALSO π
forward(C++11) β forwards a function argument (function template) β¨move_if_noexcept(C++11) β obtains an rvalue reference if the move constructor does not throw (function template) πmove(C++11) β moves a range of elements to a new location (function template) π
okay that's the whole page, you're welcome, go move some objects responsibly. and remember: this tea was served fresh from http://cppreference.com, dated 2024.06.10 β periodt. π β¨π
π¦ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms