<?xml version="1.0" encoding="UTF-8" standalone="yes"?><oembed><version><![CDATA[1.0]]></version><provider_name><![CDATA[Software is Crap]]></provider_name><provider_url><![CDATA[https://davmac.wordpress.com]]></provider_url><author_name><![CDATA[davmac]]></author_name><author_url><![CDATA[https://davmac.wordpress.com/author/davmac/]]></author_url><title><![CDATA[C++ and pass-by-reference-to-copy]]></title><type><![CDATA[link]]></type><html><![CDATA[<p>I&#8217;m sure many are familiar with the terms <em>pass-by</em><em>-reference </em>and <em>pass-by-value</em>. In <em>pass-by-reference</em> a reference to the original value is passed into a function, which potentially allows the function to modify the value. In <em>pass-by-value</em> the function instead receives a copy of the original value. C++ has pass-by-value semantics by default (except, arguably, for arrays) but function parameters can be explicitly marked as being pass-by-reference, with the &#8216;&amp;&#8217; modifier.</p>
<p>Today, I learned that C++ will in some circumstances pass by reference to a (temporary) copy.</p>
<p style="padding-left:30px;"><em>Interjection: I said &#8220;copy&#8221;, but actually the temporary object will have a different type. Technically, it is a temporary initialised using the original value, not a copy of the original value.</em></p>
<p>Consider the following program:</p>
<pre style="padding-left:30px;">#include &lt;iostream&gt;

void foo(void * const &amp;p)
{
    std::cout &lt;&lt; "foo, &amp;p = " &lt;&lt; &amp;p &lt;&lt; std::endl;
}

int main (int argc, char **argv)
{
    int * argcp = &amp;argc;
    std::cout &lt;&lt; "main, &amp;argcp = " &lt;&lt; &amp;argcp &lt;&lt; std::endl;
    foo(argcp);
    foo(argcp);
    return 0;
}</pre>
<p>What should the output be? Naively, I expected it to print the same pointer value three times. Instead, it prints this:</p>
<pre style="padding-left:30px;">main, &amp;argcp = 0x7ffc247c9af8
foo, &amp;p = 0x7ffc247c9b00
foo, &amp;p = 0x7ffc247c9b08</pre>
<p>Why? It turns out that what we end up passing is a reference to a temporary, because the pointer types aren&#8217;t compatible. That is, a &#8220;void * &amp;&#8221; cannot be a reference to an &#8220;int *&#8221; variable (essentially for the same reason that, for example, a &#8220;float &amp;&#8221; cannot be a reference to a &#8220;double&#8221; value). Because the parameter is tagged as <em>const</em>, it is safe to instead pass a temporary initialised with the value of of the argument &#8211; the value can&#8217;t be changed by the reference, so there won&#8217;t be a problem with such changes being lost due to them only affecting the temporary.</p>
<p>I can see some cases where this might cause an issue, though, and I was a bit surprised to find that C++ will do this &#8220;conversion&#8221; automatically. Perhaps it allows for various conveniences that wouldn&#8217;t otherwise be possible; for instance, it means that I can choose to change any function parameter type to a <em>const</em> reference and all existing calls will still be valid.</p>
<p>The same thing happens with a &#8220;Base * const &amp;&#8221; and &#8220;Derived *&#8221; in place of &#8220;void * const &amp;&#8221; / &#8220;int *&#8221;, and for any types which offer conversion, eg:</p>
<pre style="padding-left:30px;">#include &lt;iostream&gt;

class A {};

class B
{
    public:
    operator A()
    {
        return A();
    }
};

void foo(A const &amp;p)
{
    std::cout &lt;&lt; "foo, &amp;p = " &lt;&lt; &amp;p &lt;&lt; std::endl;
}

int main (int argc, char **argv)
{
    B b;
    std::cout &lt;&lt; "main, &amp;b = " &lt;&lt; &amp;b &lt;&lt; std::endl;
    foo(b);
    foo(b);
    return 0;
}</pre>
<p>Note this last example is not passing pointers, but (references to) object themselves.</p>
<p>Takeaway thoughts:</p>
<ul>
<li>Storing the address of a parameter received by <em>const </em>reference is probably unwise; it may refer to a temporary.</li>
<li>Similarly, storing a reference to the received parameter indirectly could cause problems.</li>
<li>In general, you cannot assume that the pointer object referred to by a <em>const</em>-reference parameter is the one actually passed as an argument, and it may not exist once the function returns.</li>
</ul>
]]></html></oembed>