Channels ▼

Andrew Koenig

Dr. Dobb's Bloggers

Syntactic Sugar Is More Than Dessert

July 11, 2012

Here are three code fragments:


               // Fragment 1
               shared_ptr<int> p(new int(42));
 
               // Fragment 2
               shared_ptr<int> q = make_shared<int>(42);
 
               // Fragment 3		auto r = make_shared<int>(42);
 

Each of these fragments ultimately has the same effect: Allocate an object of type int on the free store, initialize that object to 42, and create a variable of type shared_ptr<int> that points to that object. The only real difference between these fragments is in the syntactic sugar that they use.

Fragment 1 is the most straightforward: It explicitly constructs a variable of type shared_ptr<int> and explicitly initializes it to the address of a newly allocated int object. Its virtue is in its directness and simplicity. However, it has a hidden pitfall: Suppose we were to rewrite it this way:

 
               // Fragment 1a
int* obj = new int(42);
shared_ptr<int> p(obj);

Programmers break complicated expressions into simpler ones all the time, so this rewrite should come as no surprise. Unfortunately, once the program is rewritten this way, the variable obj contains a pointer to the allocated object — which, of course, the shared_ptr will eventually free. In other words, the obvious simplification of Fragment 1 leads to code that might fail in ways that will be difficult to detect. Indeed, detection would be particularly difficult because the memory occupied by freed objects often appears to be valid until that memory is actually reused.

Fragment 2 avoids Fragment 1a's pitfall through encapsulation: It uses the standard-library make_shared function template to encapsulate the notion of allocating memory, initializing it, and creating a shared_ptr bound to that memory. We can think of this encapsulation as a kind of syntactic sugar — but it has another useful property as well: Part of what is encapsulated is the pointer to the dynamically allocated object.

Because of this encapsulation, it is much less likely that a raw pointer will leak out of this fragment by mistake than it was for Fragment 1. On the other hand, we now have a new pitfall: Fragment 2 mentions the type int in two different places. Whenever the correctness of a piece of code relies on writing the same thing twice, there is the risk that someone might change one of those occurrences without changing the other. This hazard is pervasive enough that software engineers use the phrase DRY (Don't Repeat Yourself) to refer to it.

It won't do to look for two different types in code similar to Fragment 2 either, because it is legitimate to convert a shared_ptr to a derived class into a shared_ptr to a base class:

 
               // Fragment 2a
               shared_ptr<Base> q = make_shared<Derived>();

Now the fact that two different types appear in this declaration might be an error or it might not; and the only way to tell is to understand the rest of the code.

Fragment 3 makes our readers' job easier than Fragment 2, because it states the type int only once. By using auto, Fragment 3 makes it clear that we intend the type of r to be the same as the type returned by make_shared. Moreover, if we change the call to make_shared and recompile, we will have changed the type of r, and the compiler will use this new type to check the type of any code that uses r. Fragment 3 is probably the easiest of the three to understand, too — which is a nice bonus.

It is tempting to think of language or library features such as make_shared or auto as mere syntactic sugar. After all, at least in these simple examples, they do not allow us to do anything that we could not have done without them. However, syntactic sugar is often a form of encapsulation, and encapsulation has advantages beyond mere convenience. In particular, Fragment 3 encapsulates both the raw pointer in Fragment 1 and the potentially duplicated type in Fragment 2, and does so in a way that is easier to follow than either of the originals.

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