“May Not Meet Developer Expectations” #77

Question:  Does the following compile?

int func()
{
  int (func);
  return func;
}

The answer, rather appallingly, is:  yes.

The compiler treats the highlighted line as a declaration of an int called func; which is uninitialised.

The compiler allows this, on the grounds that if it looks (vaguely) like a declaration it is a declaration.  C++’s Most Vexing Parse is another wonderful example of such behaviour.

On a more practical note this could lead to some very subtle errors in multi-threaded code:

template <typename T>
class Monitor {
public:
 void add(const T& in_val)
 {
   std::unique_ptr<std::mutex>(mtx);  // Acquire the lock

   // Add the data...
 }

 T get()
 {
   T out_val;
   std::unique_ptr<std::mutex>(mtx);  // Acquire the lock

  // Get the data...

  return out_val;
 }

private:
  // Some data storage
  std::mutex mtx;
};

 

This looks OK, but will simply create a temporary std::unique_lock object called mtx – and then discard it.  The actual mutex (Monitor::mtx) will never be locked.  That is, despite appearances (and no compile errors or warnings), this code isn’t thread-safe.

Good luck debugging this!

A couple of notes on this issue:

  • This code only compiles because a std::unique_lock has a default constructor. std::lock_guard doesn’t have a default constructor, so this would fail to compile; albeit with a less-than-obvious error.
  • This problem is far less likely to occur with non-RAII-type classes, because you’ll get an error as soon as you attempt to call any method.
  • This would fail to compile if you use brace-initialisation.

What’s the moral of this story?  Always use brace-initialisation!

Glennan Carnie

Glennan Carnie

Technical Consultant at Feabhas Ltd
Glennan is an embedded systems and software engineer with over 20 years experience, mostly in high-integrity systems for the defence and aerospace industry.

He specialises in C++, UML, software modelling, Systems Engineering and process development.
Glennan Carnie

Latest posts by Glennan Carnie (see all)

Dislike (1)

About Glennan Carnie

Glennan is an embedded systems and software engineer with over 20 years experience, mostly in high-integrity systems for the defence and aerospace industry. He specialises in C++, UML, software modelling, Systems Engineering and process development.
This entry was posted in C/C++ Programming and tagged , , , , , . Bookmark the permalink.

3 Responses to “May Not Meet Developer Expectations” #77

  1. KaiSt says:

    I just want to mention, that specifying -Wshadow in combination with -Werror prevents such pitfalls (at least with GCC and compatible compilers).

    https://godbolt.org/g/Cq6Gk6

    Like (0)
    Dislike (0)
  2. KaiSt says:

    clang trunk gives an "vexing-parse" error: https://godbolt.org/g/9JYSu5.

    Like (0)
    Dislike (0)
  3. You probably want to replace std::unique_ptr with std::unique_lock in your snippet.
    Also, the second example is very convincing, because one must almost always give a name to a unique_lock, otherwise it is destroyed at the end of the expression, not at the end of scope.

    Like (2)
    Dislike (0)

Leave a Reply