Move Semantics
As read before, move semantics in cpp is nothing but working with something temporary and moving (pointing) it to some other variable to keep this data alive.
Note: temperary is denoted as
&&
in a cpp program.
Here is an example:
#include <iostream>
#include <cstring>
class MyString {
private:
char* data;
size_t length;
public:
// Constructor
MyString(const char* str) {
length = strlen(str);
data = new char[length + 1];
strcpy(data, str);
}
// Destructor
~MyString() {
delete[] data;
}
// Copy constructor
MyString(const MyString& other) {
length = other.length;
data = new char[length + 1];
strcpy(data, other.data);
std::cout << "Copy constructor called" << std::endl;
}
// Move constructor
MyString(MyString&& other) noexcept {
data = other.data;
length = other.length;
other.data = nullptr;
other.length = 0;
std::cout << "Move constructor called" << std::endl;
}
// Copy assignment operator
MyString& operator=(const MyString& other) {
if (this != &other) {
delete[] data;
length = other.length;
data = new char[length + 1];
strcpy(data, other.data);
}
std::cout << "Copy assignment called" << std::endl;
return *this;
}
// Move assignment operator
MyString& operator=(MyString&& other) noexcept {
if (this != &other) {
delete[] data;
data = other.data;
length = other.length;
other.data = nullptr;
other.length = 0;
}
std::cout << "Move assignment called" << std::endl;
return *this;
}
// Function to get string length
size_t size() const {
return length;
}
};
// Function that returns a MyString object
MyString createString() {
return MyString("Temporary String");
}
int main() {
MyString str1("Hello");
MyString str2 = str1; // Copy construction
MyString str3 = std::move(str1); // Move construction
MyString str4("World");
str4 = str2; // Copy assignment
str4 = createString(); // Move assignment
return 0;
}
Let me explain the key points of this example:
We've defined a
MyString
class with both copy and move semantics.Copy operations (constructor and assignment) create a new buffer and copy the data.
Move operations (constructor and assignment) transfer ownership of the buffer without copying data.
In the
main()
function:str2 = str1
uses copy constructionstr3 = std::move(str1)
uses move constructionstr4 = str2
uses copy assignmentstr4 = createString()
uses move assignment (becausecreateString()
returns a temporary)
The move operations are more efficient because they avoid allocating new memory and copying data. Instead, they simply transfer ownership of the existing data.
After a move operation, the source object (
str1
in the move construction case) is left in a valid but unspecified state. In this implementation, we set its pointer tonullptr
and length to 0.The
noexcept
specifier on move operations is a guarantee that these operations won't throw exceptions, which allows for further optimizations by the compiler.
When you run this program, you'll see which constructors and assignment operators are called in each case. The move operations will be used for temporary objects (like the one returned by createString()
), resulting in better performance.
This example demonstrates how move semantics can improve efficiency by avoiding unnecessary copying, especially when dealing with temporary objects or explicitly using std::move
.
Last updated