Channels ▼

Andrew Koenig

Dr. Dobb's Bloggers

Elegance or Trickery: Follow-Up

October 05, 2011

I think my Elegance or Trickery? post has received more comments than anything else I've written for Dr. Dobb's, so I'm going to stay on this topic for a while.

One of my favorite comments was that writing a.erase(iter++) hides a subtlety that is necessary for the code to work correctly. In particular, it is tempting to think that

a.erase(iter++);

has the same effect as

a.erase(iter);
 ++iter;

and it doesn't. The difference is that the first form increments iter before calling erase; the second increments iter afterward. Because erase invalidates iter, the second form doesn't work.

This problem is an example of a subtlety that lies behind many bugs, namely an expression that combines more than one side effect, or if its operation depends on when a side effect happens. In this particular example, erase has the side effect of invalidating iter, and iter++ and ++iter both rely on iter having a particular valid value. Therefore, for the statement to work correctly, erase's side effect has to happen after the program has incremented iter.

The side effects happen in the proper sequence in the first example, by virtue of the fact that a function's arguments are evaluated completely before the function is executed. In the second example, they are forced to happen the wrong order: First, iter is invalidated, and only then is its (now invalid) value used.

The trickery in the first example comes from the fact that an essential condition (ordering of side effects) is hidden in the code: Readers are not used to code that relies on arguments' side effects happening before the function executes. But what is the source of its elegance?

I think the answer is that it manages to achieve its effect without defining an extra variable. Remember the alternative that I presented? I can abbreviate it this way:

auto next = iter;
++next;
a.erase(iter);

This code appeared in a loop that would normally have incremented iter at the end of the loop body. Because iter is now invalid, I replaced the increment by

iter = next;

I dislike temporary variables, but on deeper reflection, what I really dislike about this code is that the temporary variable next persists through the entire loop body. This persistence means that all of the code between when next is created and when it is finally copied to iter might accidentally modify next, a possibility that makes the code that much harder to maintain.

For this reason, I would like to offer yet another alternative:

{ auto it = iter;
 ++iter;
 a.erase(it); }

The difference between this code and the earlier version is that it increments iter immediately. In that sense, it really does have the same effect as a.erase(iter++). Moreover, the curly braces limit the scope of the temporary variable it, so that we do not have to worry that the rest of the code might change the value of it.

I invite comments: Is this version better than the others? Does it qualify as elegant? Or is it still too tricky?

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 


Video