Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>In C++ it's very common what I consider an anti-pattern that uses <code>const T&amp;</code> like a smart way of just saying <code>T</code> when dealing with parameters. However a value and a reference (no matter if const or not) are two completely different things and always and blindly using references instead of values can lead to subtle bugs.</p> <p>The reason is that when dealing with references you must consider two issues that are not present with values: <strong>lifetime</strong> and <strong>aliasing</strong>.</p> <p>Just as an example one place where this anti-pattern is applied is the standard library itself, where <code>std::vector&lt;T&gt;::push_back</code> accepts as parameter a <code>const T&amp;</code> instead of a value and this can bite back for example in code like:</p> <pre><code>std::vector&lt;T&gt; v; ... if (v.size()) v.push_back(v[0]); // Add first element also as last element </code></pre> <p>This code is a ticking bomb because <code>std::vector::push_back</code> wants a const reference but doing the push_back may require a reallocation and if that happens means that after the reallocation the reference received would not be valid any more (<em>lifetime</em> issue) and you enter the Undefined Behaviour realm.</p> <p>Aliasing issues are also a source of subtle problems if const references are used instead of values. I've been bitten for example by code of this kind:</p> <pre><code>struct P2d { double x, y; P2d(double x, double y) : x(x), y(y) {} P2d&amp; operator+=(const P2d&amp; p) { x+=p.x; y+=p.y; return *this; } P2d&amp; operator-=(const P2d&amp; p) { x-=p.x; y-=p.y; return *this; } }; struct Rect { P2d tl, br; Rect(const P2d&amp; tl, const P2d&amp; br) : tl(tl), bt(br) {} Rect&amp; operator+=(const P2d&amp; p) { tl+=p; br+=p; return *this; } Rect&amp; operator-=(const P2d&amp; p) { tl-=p; br-=p; return *this; } }; </code></pre> <p>The code seems at a first glance pretty safe, <code>P2d</code> is a bidimensional point, <code>Rect</code> is a rectangle and adding/subtracting a point means translating the rectangle.</p> <p>If however to translate the rectangle back in the origin you write <code>myrect -= myrect.tl;</code> the code will not work because the translation operator has been defined accepting a reference that (in that case) is referencing a member of same instance.</p> <p>This means that after updating the topleft with <code>tl -= p;</code> the topleft will be <code>(0, 0)</code> as it should but also <code>p</code> will become at the same time <code>(0, 0)</code> because <code>p</code> is just a reference to the top-left member and so the update of bottom-right corner will not work because it will translate it by <code>(0, 0)</code> hence doing basically nothing.</p> <p>Please don't be fooled into thinking that a const reference is like a value because of the word <code>const</code>. That word exists only to give you compile errors if you try to change the referenced object <em>using that reference</em>, but doesn't mean that the referenced object is constant. More specifically the object referenced by a const ref can change (e.g. because of <em>aliasing</em>) and can even get out of existence while you are using it (<em>lifetime</em> issue).</p> <p>In <code>const T&amp;</code> the word <strong>const</strong> expresses a property of the <em>reference</em>, not of the <em>referenced object</em>: it's the property that makes impossible to use it to change the object. Probably <strong>readonly</strong> would have been a better name as <strong>const</strong> has IMO the psychological effect of pushing the idea that the object is going to be constant while you use the reference.</p> <p>You can of course get impressive speedups by using references instead of copying the values, especially for big classes. But you should always think about aliasing and lifetime issues when using references because under the cover they're just pointers to other data. For "native" data types (ints, doubles, pointers) references however are actually going to be slower than values and there's nothing to gain in using them instead of values.</p> <p>Also a const reference will always mean problems for the optimizer as the compiler is forced to be paranoid and every time any unknown code is executed it must assume that all referenced objects may have now a different value (<code>const</code> for a reference means absolutely NOTHING for the optimizer; that word is there only to help programmers - I'm personally not so sure it's such a big help, but that's another story).</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

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