Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Const correctness with temporary instances

Tags:

c++

Here is the example of the "scoped lock" idiom with common mistake: no local variable is created, so lock is not in effect. This code compiles flawlessly both with VC++ 2010 and Comeau C++ online:

class Mutex
{
public:
    void lock() {}
};

class ScopedLock
{
public:
    ScopedLock() : m_pm(0) {}
    ScopedLock(Mutex& m) : m_pm(&m) { m_pm->lock(); }

private:
    Mutex* m_pm;

private:
    ScopedLock& operator =(const ScopedLock&);
    ScopedLock(const ScopedLock&);
};

class X
{
public:
    void foo() const
    {
        ScopedLock(m_mutex);
    }

private:
    Mutex m_mutex;
};


int main()
{
    X x1;
    x1.foo();
}

If default constructor for ScopedLock is commented out, then both compilers give an error:

error C2512: 'ScopedLock' : no appropriate default constructor available

(When ScopedLock used correctly, i.e. local variable is created: ScopedLock guard(m_mutex);, then compilation fails as expected. Declaring m_mutex as mutable fixes the problem.)

I have two questions:

  1. Why X::foo compiles? It seems that compiler was able to cast const Mutex& to Mutex& somehow.

  2. What role plays ScopedLock default constructor, so the compilation succeeds?

Thanks.

Update: I found the answer. It appears that ScopedLock(m_mutex); statement creates a local variable m_mutex of type ScopedLock. Not a temporary. That's why ScopedLock::ScopedLock default constructor is required.

like image 988
Alex Blekhman Avatar asked May 19 '11 01:05

Alex Blekhman


1 Answers

You answered the question yourself.

It appears that ScopedLock(m_mutex); statement creates a local variable m_mutex of type ScopedLock

The explanation is to be found in the Standard's Section 6.8 Ambiguity Resolution:

There is an ambiguity in the grammar involving expression-statements and declarations: An expression-statement with a function-style explicit type conversion [5.2.3] as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is a declaration.

The Standard then lists T(a); as an example of a statement that is really a declaration. It is equivalent to T a;

This is one variation of the infamous C++ "most vexing parse".

like image 149
decltype Avatar answered Oct 23 '22 21:10

decltype