{"id":6808,"date":"2020-05-08T13:59:33","date_gmt":"2020-05-08T13:59:33","guid":{"rendered":"http:\/\/www.max-sperling.bplaced.net\/?p=6808"},"modified":"2024-02-16T10:25:50","modified_gmt":"2024-02-16T10:25:50","slug":"move-constructor","status":"publish","type":"post","link":"http:\/\/www.max-sperling.bplaced.net\/?p=6808","title":{"rendered":"Move semantics (C++)"},"content":{"rendered":"<p>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.<\/p>\n<hr>\n<pre class=\"brush: cpp; gutter: false; title: ; notranslate\" title=\"\">\r\n#include &lt;utility&gt;\r\n#include &lt;cstring&gt;\r\n#include &lt;memory&gt;\r\n#include &lt;mutex&gt;\r\n#include &lt;iostream&gt;\r\n \r\nclass Matrix\r\n{\r\npublic:\r\n  \/\/ Constructor\r\n  Matrix(unsigned rows, unsigned cols) : m_Mtx(), m_Rows(rows), m_Cols(cols)\r\n  {\r\n    std::cout &lt;&lt; &quot;Matrix constructor&quot; &lt;&lt; std::endl;\r\n \r\n    createMatrix();\r\n  }\r\n \r\n  \/\/ Copy-Constructor\r\n  Matrix(const Matrix&amp; other) : m_Mtx()\r\n  {\r\n    std::cout &lt;&lt; &quot;Matrix copy-constructor&quot; &lt;&lt; std::endl;\r\n \r\n    {\r\n      std::lock_guard&lt;std::mutex&gt; lock(other.m_Mtx);\r\n \r\n      m_Rows = other.m_Rows;\r\n      m_Cols = other.m_Cols;\r\n \r\n      createMatrix();\r\n      for (int i = 0; i &lt; m_Rows; i++)\r\n      {\r\n        std::memcpy(m_Mat[i], other.m_Mat[i], m_Cols * sizeof(m_Cols));\r\n      }\r\n    }\r\n  }\r\n \r\n  \/\/ Move-Constructor\r\n  Matrix(Matrix&amp;&amp; other) : m_Mtx()\r\n  {\r\n    std::cout &lt;&lt; &quot;Matrix move-constructor&quot; &lt;&lt; std::endl;\r\n \r\n    {\r\n      std::lock_guard&lt;std::mutex&gt; lock(other.m_Mtx);\r\n \r\n      m_Rows = other.m_Rows;\r\n      m_Cols = other.m_Cols;\r\n      m_Mat = other.m_Mat;\r\n \r\n      other.m_Rows = 0;\r\n      other.m_Cols = 0;\r\n      other.m_Mat = nullptr;\r\n    }\r\n  }\r\n \r\n  \/\/ Destructor\r\n  ~Matrix()\r\n  {\r\n    std::cout &lt;&lt; &quot;Matrix destructor&quot; &lt;&lt; std::endl;\r\n \r\n    removeMatrix();\r\n \r\n    m_Rows = 0;\r\n    m_Cols = 0;\r\n    m_Mat = nullptr;\r\n  }\r\nprivate:\r\n  void createMatrix()\r\n  {\r\n    m_Mat = new unsigned*[m_Rows];\r\n    for (unsigned i = 0; i &lt; m_Rows; ++i)\r\n    {\r\n      m_Mat[i] = new unsigned[m_Cols];\r\n    }\r\n  }\r\n \r\n  void removeMatrix()\r\n  {\r\n    for(unsigned i = 0; i &lt; m_Rows; ++i)\r\n    {\r\n      delete[] m_Mat[i];\r\n    }\r\n    delete[] m_Mat;\r\n  }\r\n \r\n  mutable std::mutex m_Mtx;\r\n  unsigned m_Rows;\r\n  unsigned m_Cols;\r\n  unsigned** m_Mat;\r\n};\r\n \r\nint main()\r\n{\r\n  std::cout &lt;&lt; &quot;== Step 0: Create baseMatrix (on stack) ==&quot; &lt;&lt; std::endl;\r\n  Matrix baseMatrix(100000, 10000);\r\n \r\n  std::cout &lt;&lt; &quot;== Step 1: Copy baseMatrix to destMatrix1 ==&quot; &lt;&lt; std::endl;\r\n  Matrix destMatrix1(baseMatrix); \/\/ Very slow\r\n \r\n  std::cout &lt;&lt; &quot;== Step 2: Move baseMatrix to destMatrix2 ==&quot; &lt;&lt; std::endl;\r\n  Matrix destMatrix2(std::move(baseMatrix)); \/\/ Very fast\r\n  \/\/ std::move() makes baseMatrix an rValue reference,\r\n  \/\/ which is empty after the move-c&#039;tor\r\n\r\n  std::cout &lt;&lt; &quot;== Step 3: Cleanup in stack order ==&quot; &lt;&lt; std::endl;\r\n  return 0;\r\n}\r\n<\/pre>\n<pre>\r\n== Step 0: Create baseMatrix (on stack) ==\r\nMatrix constructor\r\n== Step 1: Copy baseMatrix to destMatrix1 ==\r\nMatrix copy-constructor\r\n== Step 2: Move baseMatrix to destMatrix2 ==\r\nMatrix move-constructor\r\n== Step 3: Cleanup in stack order ==\r\nMatrix destructor\r\nMatrix destructor\r\nMatrix destructor\r\n<\/pre>\n<p>This example just contains the move constructor, but normally you want to implement a move assignment operator as well.<\/p>\n<p><u>Alternative<\/u>: Let the compiler implicitly create a move constructor \/ move assignment operator for you. Be aware of the requirements and restrictions.<\/p>\n<hr>\n<p>Don&#8217;t use std::move when <a href=\"http:\/\/www.max-sperling.bplaced.net\/?p=13835\">(Named) Return Value Optimization<\/a> comes in place, cause it&#8217;s even faster. (Just constructor instead of constructor + move operation.)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Since C++11 we can now use move semantics (move constructor, move assignment operator). They provide a perfomance boost over copy<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false},"categories":[27],"tags":[],"_links":{"self":[{"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts\/6808"}],"collection":[{"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=6808"}],"version-history":[{"count":1,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts\/6808\/revisions"}],"predecessor-version":[{"id":16751,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts\/6808\/revisions\/16751"}],"wp:attachment":[{"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=6808"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=6808"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=6808"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}