Validity with temporary instances

Here is an example of an idiom with limited visibility with a common error: a local variable is not created, so the lock does not work. This code compiles perfectly with both VC ++ 2010 and Comeau C ++ on the Internet:

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 the default constructor for ScopedLock is commented out, then both compilers throw an error:

error C2512: 'ScopedLock': no ​​suitable default constructor exists

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

I have two questions:

  • Why is X::foo compiling? It seems that the compiler was able to somehow cast const Mutex& into Mutex& .

  • What role does the default constructor of ScopedLock , so ScopedLock compilation succeed?

Thanks.

Update: I found the answer. It looks like the ScopedLock(m_mutex); creates a local variable m_mutex type ScopedLock . Not temporary. Therefore, the ScopedLock::ScopedLock constructor of ScopedLock::ScopedLock is required.

+6
source share
3 answers

You yourself answered the question.

It looks like ScopedLock (m_mutex); operator creates a local variable m_mutex of type ScopedLock

An explanation can be found in standard section 6.8. Ambiguity Resolution:

There is an ambiguity in the grammar, including expression expressions and declarations: expression expression with an explicit type conversion in the style of the function [5.2.3] as its leftmost subexpression may be indistinguishable from the declaration in which the first declarator begins with a (. A statement is an announcement .

Then the standard displays T(a); as an example of a statement that really is a declaration. This is equivalent to T a;

This is one of the variants of the infamous C ++ “most unpleasant parsing”.

+4
source

I am sure your problem is line 26: ScopedLock(m_mutex);

Instead, it should be something like ScopedLock a_variable_name(m_mutex);

When I make this change, I get the expected errors:

 constCorrectness.cpp: In member function 'void X::foo() const': constCorrectness.cpp:26: error: no matching function for call to 'ScopedLock::ScopedLock(const Mutex&)' constCorrectness.cpp:18: note: candidates are: ScopedLock::ScopedLock(const ScopedLock&) constCorrectness.cpp:11: note: ScopedLock::ScopedLock(Mutex&) constCorrectness.cpp:10: note: ScopedLock::ScopedLock() 

Perhaps someone can interpret ScopedLock(m_mutex) for us? Does it declare any function or something else? Instead of calling the constructor, as the interrogator expected? Update:. I think this is just a variable declaration (i.e., Brackets are ignored.)

+1
source

The problem is that the X :: foo () method is declared as const - this means that it will not mutate (modify) the object.

The ScopedLock () constructor does not have an overload that accepts an immutable (const) reference to a Mutex object.

This requires declaring m_mutex as mutable or providing the appropriate overloaded ScopedLock () constructor. I think the former is preferable.

0
source

Source: https://habr.com/ru/post/888492/


All Articles