Since C++11 we can now use move semantics (move constructor, move assignment operator). They provide a perfomance boost over copy semantics, but only work on rvalue references.
#include <utility> #include <cstring> #include <memory> #include <mutex> #include <iostream> class Matrix { public: // Constructor Matrix(unsigned rows, unsigned cols) : m_Mtx(), m_Rows(rows), m_Cols(cols) { std::cout << "Matrix constructor" << std::endl; createMatrix(); } // Copy-Constructor Matrix(const Matrix& other) : m_Mtx() { std::cout << "Matrix copy-constructor" << std::endl; { std::lock_guard<std::mutex> lock(other.m_Mtx); m_Rows = other.m_Rows; m_Cols = other.m_Cols; createMatrix(); for (int i = 0; i < m_Rows; i++) { std::memcpy(m_Mat[i], other.m_Mat[i], m_Cols * sizeof(m_Cols)); } } } // Move-Constructor Matrix(Matrix&& other) : m_Mtx() { std::cout << "Matrix move-constructor" << std::endl; { std::lock_guard<std::mutex> lock(other.m_Mtx); m_Rows = other.m_Rows; m_Cols = other.m_Cols; m_Mat = other.m_Mat; other.m_Rows = 0; other.m_Cols = 0; other.m_Mat = nullptr; } } // Destructor ~Matrix() { std::cout << "Matrix destructor" << std::endl; removeMatrix(); m_Rows = 0; m_Cols = 0; m_Mat = nullptr; } private: void createMatrix() { m_Mat = new unsigned*[m_Rows]; for (unsigned i = 0; i < m_Rows; ++i) { m_Mat[i] = new unsigned[m_Cols]; } } void removeMatrix() { for(unsigned i = 0; i < m_Rows; ++i) { delete[] m_Mat[i]; } delete[] m_Mat; } mutable std::mutex m_Mtx; unsigned m_Rows; unsigned m_Cols; unsigned** m_Mat; }; int main() { std::cout << "== Step 0: Create baseMatrix (on stack) ==" << std::endl; Matrix baseMatrix(100000, 10000); std::cout << "== Step 1: Copy baseMatrix to destMatrix1 ==" << std::endl; Matrix destMatrix1(baseMatrix); // Very slow std::cout << "== Step 2: Move baseMatrix to destMatrix2 ==" << std::endl; Matrix destMatrix2(std::move(baseMatrix)); // Very fast // std::move() makes baseMatrix an rValue reference, // which is empty after the move-c'tor std::cout << "== Step 3: Cleanup in stack order ==" << std::endl; return 0; }
== Step 0: Create baseMatrix (on stack) == Matrix constructor == Step 1: Copy baseMatrix to destMatrix1 == Matrix copy-constructor == Step 2: Move baseMatrix to destMatrix2 == Matrix move-constructor == Step 3: Cleanup in stack order == Matrix destructor Matrix destructor Matrix destructor
This example just contains the move constructor, but normally you want to implement a move assignment operator as well.
Alternative: Let the compiler implicitly create a move constructor / move assignment operator for you. Be aware of the requirements and restrictions.
Don’t use std::move when (Named) Return Value Optimization comes in place, cause it’s even faster. (Just constructor instead of constructor + move operation.)