Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>The difference lies to what the <code>&amp;</code> qualifier applies to : A type, or a variable?</p> <p>Let's say you have a type <code>T</code>.</p> <p>For declarations/parameters (<code>&amp;</code> is a type qualifier) :</p> <pre><code>T v1 = 13 ; // v1 is a variable of type T, whose value is 13 T v2 = 42 ; // v2 is another variable of type T, whose value is 42 T * v3 ; // v3 is an uninitialized pointer to a variable of type T T * v4 = &amp;v1; // v4 is pointer pointing to v1 (the value of v4 is the // address of v1) T &amp; v5 = v1 ; // v5 is an alias of v1 T &amp; v6 ; // WON'T COMPILE. An alias MUST be initialized. </code></pre> <p>For operations (<code>&amp;</code> is then an operator) :</p> <pre><code>&amp;v1 ; // returns the address of v1 (e.g. 0x00ABCDEF) v4 ; // returns 0x00ABCDEF (because v4 was initialized to point to // v1) *v4 ; // returns the dereferenced value of pointer v4, that is: 13 v5 ; // returns the value inside v1 (the aliased variable of v5), // that is: 13 </code></pre> <p>We can now mix the two notations :</p> <pre><code>// We can reattribute the variables pointed by pointers T * v7 = &amp;v1 ; // v7 is a pointer to the variable v1 *v7 ; // returns v1's value, that is 13 v7 = &amp;v2 ; // v7 is now pointing to v2 *v7 ; // returns v2's value, that is 42 // We cannot reattribute the aliases referencing variables // because once initialized, aliases **are** the variable they // were initialized to. v5 = v2 ; // v5 is an alias of v1, so this won't reattribute it // instead, it will put the value of v2 into v5 and // thus v1 // this, writing v5 = v2 is like writing v1 = v2 v2 ; // v2 is still 42 v1 ; // v1 has a value of 42 (since the v5 = v2 line above) v5 ; // v5 is still the alias of v1, and thus, its value is 42 v2 = 57 ; // v2's value is now 57 v1 ; // v1's value is still 42 (changing v2 has no impact on // v1 because they are NOT aliases. They are distinct // variables v5 ; // v5 is still the alias of v1, and thus, its value is // still 42 </code></pre> <h1>Detail : About C</h1> <p>The C language had only the notion of value, and pointer to value (and pointer to pointer to value, and pointer to... etc.), meaning that you had a notion of referencing/dereferencing (unrelated to C++ references...) with unary operators <code>&amp;</code> and <code>*</code>.</p> <pre><code>T ** p ; // is the declaration of a pointer to a pointer // to a value of type T p ; // is still the pointer to pointer &amp;p ; // returns the address of the p variable // meaning you can put that address in a variable // of type T ***: T *** pp = &amp;p ; &amp;&amp;p ; // This has no meaning whatsoever in C and C++ // because an address is a simple raw number, and a // a number has no address: Only variables have // addresses *p ; // this is p, dereferenced once, meaning you get // to have the value at the address given by p, which // is still an address (a pointer of type T *) **p ; // this is p, dereferenced twice, meaning you get // to have the value at the address given by *p, // which is of type T </code></pre> <p>The problem is that unary operators <code>&amp;</code> and <code>*</code> are not really symetrical. For example :</p> <pre><code>T t = v ; T * p = &amp;t ; T * p2 = &amp;t ; // p and p2 are two different pointers containing // the same address, and thus pointing at the same // value v p == p2 ; // is true, because both different pointers contain // the same address *p == *p2 ; // is true, because both different pointers point // to the same value (as they contain the same // address) &amp;p == &amp;p2 ; // is false, because each variable p and p2 is // distinct from the other, and thus, have different // addresses </code></pre> <p>So, in C :</p> <ul> <li>unary operator <code>*</code> will retrieve a value at the address contained by a pointer variable</li> <li>unary operator <code>&amp;</code> will retrieve the address of a variable</li> </ul> <h1>Detail : About C++</h1> <p>In C++, for multiple reasons (but the need was first discovered for operators, but there are multiple other reasons, like value constructors, and mostly avoiding polluting the code with pointers and useless NULL tests), there is a notion of (C++) reference, that is, an alias to a value :</p> <p><b>In C++, in addition to applying the <code>&amp;</code> qualitifer to a variable (which retrieves its address), you can apply it instead to a type (which makes its variable a reference/alias)</b>.</p> <p>So, when you have :</p> <pre><code>T t = v ; T * p = &amp;t ; // p is a pointer containing the address of the t // variable T ** pp = &amp;p ; // pp is a pointer containing the address of the p // variable T &amp; r = t ; // r is a reference to/an alias of t. It behaves as // if it was t in all aspects T *&amp; r = p ; // If you understand that line, then you're ready for // C++ references (i.e. r is an alias of a pointer to T, // here, an alias of p) T **&amp; rr = pp ; // rr is an alias of a pointer to a pointer to T, // here, an alias of pp) </code></pre> <p>I'm guessing here, but it is quite probable the references <code>r</code> and <code>rr</code> are optimized away at compile time (i.e. only <code>t</code> and <code>p</code> remains)</p> <h1>Detail : About C++11 (<a href="http://herbsutter.com/2011/08/12/we-have-an-international-standard-c0x-is-unanimously-approved/" rel="noreferrer">formerly known as C++0x</a>)</h1> <p>As this question was tagged <code>C++0x</code>, I'll speak about it, and the new <code>&amp;&amp;</code> r-value reference.</p> <p>The references/aliases did not change from C++ to C++11. But there is another type of "reference" that was introduced (as the <code>&amp;&amp;</code> type qualifier), that is, the r-value reference, in addition to C++ simple references/aliases.</p> <p>Because C++ has value semantics, some processing can be quite expensive. For example, you can have a lot of useless temporaries if you write your code the wrong way.</p> <p>The move semantics were added to handle this problem: Why creating a lot of copies of the same object, if in the end, we will dump the copies to the garbage, and only keep the last one ?</p> <p>For example, the following code:</p> <pre><code> 1 | T foo() 2 | { 3 | T a ; 4 | // put some values in T 5 | return a ; 6 | } 7 | 8 | void bar() 9 | { 10 | T b = foo() ; 11 | } </code></pre> <p>Barring optimizations (<a href="https://secure.wikimedia.org/wikipedia/en/wiki/Return_value_optimization" rel="noreferrer">return-value-optimization</a> comes to mind, but also <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Inlining" rel="noreferrer">inlining</a>), this code will create a value <code>a</code> (line 3) or type <code>T</code>. As it returns a type <code>T</code> (line 5), it will make a temporary copy of <code>a</code>, which we'll call <code>x</code>, and then destroy <code>a</code>.</p> <p>At line 10, the value <code>b</code> will be initialized using the temporary value <code>x</code> (which is the so called r-value), and then, <code>x</code> will be destroyed.</p> <p>Meaning that to initialize <code>b</code>, you created two variables, one explicitly (<code>a</code>) and one implicitely <code>x</code>) that were destroyed soon after, which can be expensive if the construction of a type <code>T</code> is expensive.</p> <p><i>(As an amusing side node, I had to add a lot of complexity to this example to stop g++ from optimizing through r-v-o and demonstrate the move semantics effect on my example code...)</i></p> <p>The solution is to create a move constructor (and probably a move <code>operator =</code>, for completeness), that is, something with the following prototype:</p> <pre><code>T::T(T &amp;&amp; p_t) ; // move constructor T &amp; T::operator = (T &amp;&amp; p_t) ; // move operator = </code></pre> <p>Which can be compared to C++ usual copy constructors/<code>operator =</code>:</p> <pre><code>T::T(const T &amp; p_t) ; // copy constructor T &amp; T::operator = (const T &amp; p_t) ; // operator = </code></pre> <p>So back to the example above, we add move semantics to T:</p> <pre><code>class T { V * m_v ; // some complex data, expensive to create // and expensive to destroy // etc. } // destructor : // Clean its internals if needed T::~T() { delete this-&gt;m_v ; // potentially expensive if m_v is not NULL } // copy constructor : // Do not modify the original, and make a copy of its internals T::T(const T &amp; p_t) { this-&gt;m_v = new V(p_t.m_v) ; // potentially expensive } // move constructor // the original is a temporary (guaranteed by the compiler) // so you can steal its internals, as long as you keep the // temporary clean, no one cares T::T(T &amp;&amp; t) { this-&gt;m_v = t.m_v ; // stealing the internals of the temporary t.m_v = NULL ; // the temporary is now "empty" } </code></pre> <p>This way, the code above (with <code>foo</code> and <code>bar</code>, without any change) will avoid creating two temporary objects of type T, because of T's support of move semantics.</p> <p>P.S.: adding a move constructor means you should add a move <code>operator =</code>, too.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload