{"id":13835,"date":"2022-06-16T12:45:21","date_gmt":"2022-06-16T12:45:21","guid":{"rendered":"http:\/\/www.max-sperling.bplaced.net\/?p=13835"},"modified":"2024-02-18T11:32:41","modified_gmt":"2024-02-18T11:32:41","slug":"named-return-value-optimization","status":"publish","type":"post","link":"http:\/\/www.max-sperling.bplaced.net\/?p=13835","title":{"rendered":"Return value optimization (RVO)"},"content":{"rendered":"<p>It&#8217;s a part of the copy elision, which is a compiler optimization strategy defined in the C++ standard.<\/p>\n<hr>\n<pre class=\"brush: cpp; gutter: false; title: ; notranslate\" title=\"\">\r\nclass T {\r\n    public:\r\n        T() : m_answer(42) {}\r\n    private:\r\n        int m_answer;\r\n};\r\n\r\nT createNamedT() {\r\n    T t;\r\n    return t;\r\n}\r\n\r\nT createUnnamedT() {\r\n    return T();\r\n}\r\n\r\nint main() {\r\n    T t2 = createNamedT();\r\n    T t1 = createUnnamedT();\r\n    return 0;\r\n}\r\n<\/pre>\n<hr>\n<details>\n<summary><strong>Scenario 1<\/strong> (gcc 5.1 (x86-64), flags: &#8216;-fno-elide-constructors&#8217;) \u25bc<\/summary>\n<pre>\r\nT::T() [base object constructor]:\r\n        push    rbp\r\n        mov     rbp, rsp\r\n        mov     QWORD PTR [rbp-8], rdi\r\n        mov     rax, QWORD PTR [rbp-8]\r\n        mov     DWORD PTR [rax], 42\r\n        nop\r\n        pop     rbp\r\n        ret\r\nT::T(T const&) [base object constructor]:\r\n        push    rbp\r\n        mov     rbp, rsp\r\n        mov     QWORD PTR [rbp-8], rdi\r\n        mov     QWORD PTR [rbp-16], rsi\r\n        mov     rax, QWORD PTR [rbp-8]\r\n        mov     rdx, QWORD PTR [rbp-16]\r\n        mov     edx, DWORD PTR [rdx]\r\n        mov     DWORD PTR [rax], edx\r\n        nop\r\n        pop     rbp\r\n        ret\r\ncreateNamedT():\r\n        push    rbp\r\n        mov     rbp, rsp\r\n        sub     rsp, 32\r\n        lea     rax, [rbp-32]\r\n        mov     rdi, rax\r\n        call    T::T() [complete object constructor]\r\n        lea     rdx, [rbp-32]\r\n        lea     rax, [rbp-16]\r\n        mov     rsi, rdx\r\n        mov     rdi, rax\r\n        call    T::T(T const&) [complete object constructor]\r\n        mov     eax, DWORD PTR [rbp-16]\r\n        leave\r\n        ret\r\ncreateUnnamedT():\r\n        push    rbp\r\n        mov     rbp, rsp\r\n        sub     rsp, 32\r\n        lea     rax, [rbp-16]\r\n        mov     rdi, rax\r\n        call    T::T() [complete object constructor]\r\n        lea     rdx, [rbp-16]\r\n        lea     rax, [rbp-32]\r\n        mov     rsi, rdx\r\n        mov     rdi, rax\r\n        call    T::T(T const&) [complete object constructor]\r\n        mov     eax, DWORD PTR [rbp-32]\r\n        leave\r\n        ret\r\nmain:\r\n        push    rbp\r\n        mov     rbp, rsp\r\n        sub     rsp, 64\r\n        call    createNamedT()\r\n        mov     DWORD PTR [rbp-32], eax\r\n        lea     rdx, [rbp-32]\r\n        lea     rax, [rbp-48]\r\n        mov     rsi, rdx\r\n        mov     rdi, rax\r\n        call    T::T(T const&) [complete object constructor]\r\n        call    createUnnamedT()\r\n        mov     DWORD PTR [rbp-16], eax\r\n        lea     rdx, [rbp-16]\r\n        lea     rax, [rbp-64]\r\n        mov     rsi, rdx\r\n        mov     rdi, rax\r\n        call    T::T(T const&) [complete object constructor]\r\n        mov     eax, 0\r\n        leave\r\n        ret\r\n<\/pre>\n<p><u>Summary<\/u><\/p>\n<ul>\n<li>To call createNamedT()\/createUnnamedT() 1 default c&#8217;tor and 2 copy c&#8217;tors are used.<\/li>\n<\/ul>\n<\/details>\n<details>\n<summary><strong>Scenario 2<\/strong> (gcc 12.2 (x86-64), flags: &#8216;-fno-elide-constructors&#8217;) \u25bc<\/summary>\n<pre>\r\nT::T() [base object constructor]:\r\n        push    rbp\r\n        mov     rbp, rsp\r\n        mov     QWORD PTR [rbp-8], rdi\r\n        mov     rax, QWORD PTR [rbp-8]\r\n        mov     DWORD PTR [rax], 42\r\n        nop\r\n        pop     rbp\r\n        ret\r\nT::T(T&&) [base object constructor]:\r\n        push    rbp\r\n        mov     rbp, rsp\r\n        mov     QWORD PTR [rbp-8], rdi\r\n        mov     QWORD PTR [rbp-16], rsi\r\n        mov     rax, QWORD PTR [rbp-8]\r\n        mov     rdx, QWORD PTR [rbp-16]\r\n        mov     edx, DWORD PTR [rdx]\r\n        mov     DWORD PTR [rax], edx\r\n        nop\r\n        pop     rbp\r\n        ret\r\ncreateNamedT():\r\n        push    rbp\r\n        mov     rbp, rsp\r\n        sub     rsp, 16\r\n        lea     rax, [rbp-8]\r\n        mov     rdi, rax\r\n        call    T::T() [complete object constructor]\r\n        lea     rdx, [rbp-8]\r\n        lea     rax, [rbp-4]\r\n        mov     rsi, rdx\r\n        mov     rdi, rax\r\n        call    T::T(T&&) [complete object constructor]\r\n        mov     eax, DWORD PTR [rbp-4]\r\n        leave\r\n        ret\r\ncreateUnnamedT():\r\n        push    rbp\r\n        mov     rbp, rsp\r\n        sub     rsp, 16\r\n        lea     rax, [rbp-4]\r\n        mov     rdi, rax\r\n        call    T::T() [complete object constructor]\r\n        mov     eax, DWORD PTR [rbp-4]\r\n        leave\r\n        ret\r\nmain:\r\n        push    rbp\r\n        mov     rbp, rsp\r\n        sub     rsp, 16\r\n        call    createNamedT()\r\n        mov     DWORD PTR [rbp-4], eax\r\n        call    createUnnamedT()\r\n        mov     DWORD PTR [rbp-8], eax\r\n        mov     eax, 0\r\n        leave\r\n        ret\r\n<\/pre>\n<p><u>Summary<\/u><\/p>\n<ul>\n<li>To call createNamedT() 1 default c&#8217;tor and 1 move c&#8217;tor are used.<\/li>\n<li>To call createNamedT() just 1 default c&#8217;tor is used.<\/li>\n<\/ul>\n<\/details>\n<details>\n<summary><strong>Scenario 3<\/strong> (gcc 5.1 (x86-64), flags: none) \u25bc<\/summary>\n<pre>\r\nT::T() [base object constructor]:\r\n        push    rbp\r\n        mov     rbp, rsp\r\n        mov     QWORD PTR [rbp-8], rdi\r\n        mov     rax, QWORD PTR [rbp-8]\r\n        mov     DWORD PTR [rax], 42\r\n        nop\r\n        pop     rbp\r\n        ret\r\ncreateNamedT():\r\n        push    rbp\r\n        mov     rbp, rsp\r\n        sub     rsp, 16\r\n        lea     rax, [rbp-16]\r\n        mov     rdi, rax\r\n        call    T::T() [complete object constructor]\r\n        mov     eax, DWORD PTR [rbp-16]\r\n        leave\r\n        ret\r\ncreateUnnamedT():\r\n        push    rbp\r\n        mov     rbp, rsp\r\n        sub     rsp, 16\r\n        lea     rax, [rbp-16]\r\n        mov     rdi, rax\r\n        call    T::T() [complete object constructor]\r\n        mov     eax, DWORD PTR [rbp-16]\r\n        leave\r\n        ret\r\nmain:\r\n        push    rbp\r\n        mov     rbp, rsp\r\n        sub     rsp, 32\r\n        call    createNamedT()\r\n        mov     DWORD PTR [rbp-16], eax\r\n        call    createUnnamedT()\r\n        mov     DWORD PTR [rbp-32], eax\r\n        mov     eax, 0\r\n        leave\r\n        ret\r\n<\/pre>\n<p><u>Summary<\/u><\/p>\n<ul>\n<li>To call createNamedT()\/createUnnamedT() just 1 default c&#8217;tor is used.<\/li>\n<\/ul>\n<details>\n<summary><u>Note<\/u> \u25bc<\/summary>\n<p>If you change CreateNamedT() like that (to be smart):<\/p>\n<pre class=\"brush: cpp; gutter: false; title: ; notranslate\" title=\"\">\r\nT createNamedT() {\r\n    T t;\r\n    return std:move(t);\r\n}\r\n<\/pre>\n<p>The compiler (with flag &#8216;-Wall&#8217;) complains like that:<\/p>\n<pre>\r\nwarning: moving a local object in a return statement prevents copy elision [-Wpessimizing-move]\r\n      |     return std::move(t);\r\n      |            ~~~~~~~~~^~~.<\/li>\r\n<\/pre>\n<\/details>\n<\/details>\n<hr>\n<p>Used tool: <a href=\"https:\/\/godbolt.org\/\">https:\/\/godbolt.org\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>It&#8217;s a part of the copy elision, which is a compiler optimization strategy defined in the C++ standard. Scenario 1<\/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":[39],"tags":[],"_links":{"self":[{"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts\/13835"}],"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=13835"}],"version-history":[{"count":1,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts\/13835\/revisions"}],"predecessor-version":[{"id":16736,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts\/13835\/revisions\/16736"}],"wp:attachment":[{"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=13835"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=13835"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=13835"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}