← Back to C++ Course | Chapter 16: Modern C++ | Lesson 4 of 9

C++ Move Semantics

Move semantics lets C++ hand over a thing's insides instead of copying them, like giving someone your whole box instead of duplicating it. It is much faster for big things.
Syntax
cpp
data_type destination = std::move(source);  // transfers resources, source is left empty

What is Move Semantics?

Move semantics lets the compiler transfer ownership of a resource -- like heap-allocated memory inside a std::vector or std::string -- from a temporary object directly into a new one, instead of performing a full deep copy.

For large objects, this turns an O(n) copy into an O(1) pointer swap.

Example: What is Move Semantics?

cpp
// Include std::cout and std::cin
#include <iostream>
// Include std::vector
#include <vector>

// Program execution starts in main()
int main() {
	// Create a vector named source (a resizable array)
	std::vector<int> source = {1, 2, 3};
	// Create a vector named destination (a resizable array)
	std::vector<int> destination = std::move(source);
	// Print to the console with cout
	std::cout << destination.size() << std::endl;
	// Return 0 to signal that the program finished successfully
	return 0;
}

The std::move Function

std::move() doesn't physically move any data by itself -- it's purely a cast that tells the compiler "treat this lvalue as an rvalue," making it eligible to be moved from.

The actual transfer of ownership happens inside whatever move constructor or move assignment operator subsequently receives it.

Example: The std::move Function

cpp
// Include std::cout and std::cin
#include <iostream>
// Include std::string
#include <string>
#include <utility>

// Program execution starts in main()
int main() {
	std::string a = "Hello";
	// std::move transfers the resource instead of copying it
	std::string b = std::move(a);
	// Print to the console with cout
	std::cout << b << std::endl;
	// Return 0 to signal that the program finished successfully
	return 0;
}

Move Constructor

A move constructor takes ownership of a temporary object's internal resources (like a raw pointer to heap memory) by copying that pointer into the new object, then setting the temporary's own pointer to nullptr so its destructor won't accidentally free memory the new object now owns.

Example: Move Constructor

cpp
// Include std::cout and std::cin
#include <iostream>

// Define the type Buffer
class Buffer {
// Members below can be accessed from outside the class
public:
	int *data;
	// Allocate an object on the heap with new
	Buffer(int val) { data = new int(val); }
	Buffer(Buffer &&other) noexcept {
		data = other.data;
		other.data = nullptr;
	}
	~Buffer() { delete data; }
};

// Program execution starts in main()
int main() {
	Buffer a(5);
	// std::move transfers the resource instead of copying it
	Buffer b(std::move(a));
	// Print to the console with cout
	std::cout << *b.data << std::endl;
	// Return 0 to signal that the program finished successfully
	return 0;
}

Move Assignment Operator

The move assignment operator first releases whatever resources the target object currently holds (to avoid a leak), then steals the source object's resources the same way a move constructor does -- this is why move assignment is typically written to reuse the move constructor's logic.

Example: Move Assignment Operator

cpp
// Include std::cout and std::cin
#include <iostream>

// Define the type Buffer
class Buffer {
// Members below can be accessed from outside the class
public:
	int *data;
	// Allocate an object on the heap with new
	Buffer(int val) { data = new int(val); }
	Buffer &operator=(Buffer &&other) noexcept {
		// Free the heap memory with delete
		delete data;
		data = other.data;
		other.data = nullptr;
		// Send *this back to the caller
		return *this;
	}
	~Buffer() { delete data; }
};

// Program execution starts in main()
int main() {
	Buffer a(5), b(10);
	// std::move transfers the resource instead of copying it
	b = std::move(a);
	std::cout << *b.data << std::endl;
	return 0;
}

Performance Benefits

For types holding large buffers -- strings, vectors, and similar containers -- move semantics avoids the deep copy those types would otherwise require, which matters most when returning large objects from functions or storing them in containers that resize and relocate elements.

Example: Performance Benefits

cpp
// Include std::cout and std::cin
#include <iostream>
// Include std::string
#include <string>

std::string buildGreeting() {
	std::string result = "Hello, World!";
	// Send result back to the caller
	return result;
}

// Program execution starts in main()
int main() {
	std::string message = buildGreeting();
	// Print to the console with cout
	std::cout << message << std::endl;
	// Return 0 to signal that the program finished successfully
	return 0;
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Using an object after moving from it, when its value is unspecified.
  2. Forgetting noexcept on move constructors, so containers may copy instead of move.
  3. Trying to move a const object, which silently copies.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.