Search code examples
c++boostboost-mutex

C++ / boost::scoped_lock : compiler warnings missing


I'm wondering if it is possible to configure the c++ compiler so that it emits a warning when someone instatiates a scoped_lock but forgets to assign it to a variable.

See the examples below:

  • Case 1.1 and case 2.1 show the intended use of the scoped_lock
  • Case 1.2 is a faulty use where no holder variable is created. It is detected correctly by the compiler as an error (mMutex has a previous declaration)
  • Case 2.2 is almost the same error as case 1.2, but the compiler does not detect and does not emit any warning, although the code is clearly faulty, and very close to case 1.2 (and of course the mutex lock will not work).

See code below, I have tested it with g++-4.8 and visual studio 2010. Neither of them detects the faulty case 2.2.

Does anyone know why case 2.2 compiles, and what could be done in order to let the compiler detect it as a warning?

#include  <boost/thread/recursive_mutex.hpp>
void Mutex1()
{
  boost::recursive_mutex mMutex;

  //Case 1.1 : correct mutex creation
  boost::recursive_mutex::scoped_lock lock(mMutex);

  //Case 1.2 : incorrect mutex creation
  //==> leads to a compile error : "mMutex has a previous declaration" : perfect
  boost::recursive_mutex::scoped_lock(mMutex);    
}

class FooMutex
{
    boost::recursive_mutex mMutex;
    void TestMutex()
    {
        //Case 2.1 : correct mutex creation
        boost::recursive_mutex::scoped_lock lock(mMutex);//compiles correctly => ok

        //Case 2.2 : incorrect mutex creation
        //is compiled without warning ! Ouch !!!
        boost::recursive_mutex::scoped_lock(mMutex);
    }
};

Solution

  • This line:

    boost::recursive_mutex::scoped_lock(mMutex);
    

    is equivalent to this line:

    boost::recursive_mutex::scoped_lock mMutex;
    

    as such, what would the compiler warning or error be? In the first case it's an error because you're trying to redeclare mMutex, but in the second case it's perfectly reasonable code since scoped_lock is default-constructible. It's only wrong for the specific logic in your function. The compiler can't read your mind.

    If you want to simply prevent a scoped_lock from being default constructed, you could just make your own that isn't:

    template <typename T>
    struct my_unique_lock : boost::unique_lock<T> {
         using boost::unique_lock<T>::unique_lock;
    
         my_unique_lock() = delete;
    };
    
    struct my_recursive_mutex : boost::recursive_mutex {
        using scoped_lock = my_unique_lock<my_recursive_mutex>;
    };
    

    That way,

    my_recursive_mutex mMutex;
    {
        my_recursive_mutex::scoped_lock(mMutex);
    }
    

    won't compile, since the default constructor is deleted.