“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
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 (1)
    Dislike (0)

Leave a Reply