0

I have the following class that has the private member - QMutex - m_mutex_A;

class A
{
  public:
QMutex get_handle();

private:

 QMutex m_mutex_A;

}

QMutex A::get_handle()
{
  return m_mutex_A;
}

However, on building this snippet, I get the problem saying that the error: 'QMutex::QMutex(const QMutex&)' is private

On google, I found that one of the way is to make QMutex m_mutex_A; as mutable QMutex m_mutex_A; However, this doesn't work. Another strange part is that when I move this m_mutex_A to public then there is no problem. Also, the code works. What is the issue here? Can you please throw some light on it? I guess, I am missing some fundamentals here.

dexterous
  • 6,422
  • 12
  • 51
  • 99

3 Answers3

2

You'll need to return a reference. QMutex doesn't provide an accessible copy constructor (which wouldn't make sense of course):

class A {
public:
    QMutex& get_handle() { return m_mutex_A; }

private:
    QMutex m_mutex_A;
};

The mutable keyword is needed if you want to use the mutex internally within const methods.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • 1
    Actually, it does provide a copy constructor, but declared with Q_DISABLE_COPY. If it wasn't provided, a default would exist. You can see the source code for QMutex here: https://qt.gitorious.org/qt/qt/source/c1b067ea8169e1d37e2a120334406f1f115298bb:src/corelib/thread/qmutex.h#L89 and the definition of Q_DISABLE_COPY here: http://qt-project.org/doc/qt-5.0/qtcore/qobject.html#Q_DISABLE_COPY – TheDarkKnight Mar 26 '14 at 11:30
2

The error is telling you that the copy constructor for QMutex is private, so while you can declare the object as a private member, you can't return a copy in get_handle. You could, however return a reference: QMutex&

You can read about why a copy constructor is declared private here.

I'm guessing that you've misunderstood the context of the google article with reference to mutable. The mutable keyword allows modification of a variable from within a const function as well as "the differentiation of bitwise const and logical const" as answered here.

Community
  • 1
  • 1
TheDarkKnight
  • 27,181
  • 6
  • 55
  • 85
1

Mutexes are not supposed to be copied. A mutex is not a handle. Don't treat it like one.

If a mutex in class A serializes access to it, then it should only be used in the methods within that class. The users of the class should not need to worry about it. When making copies of the class, the mutex must not be copied - thus you must write your own copy and move constructors, and an assignment operator.

class A {
  mutable QMutex m_mutex;
  int m_foo;
  bool m_bar;
public:
  A() : m_foo(0), m_bar(false) {}
  A(const A& other) { *this = other; }
  A& operator=(const A & rhs) {
    if (this == &rhs) return *this;
    // This guarantees that mutexes for two instances are
    // always acquired in the same order. This prevents
    // a certain class of deadlocks.
    // See http://www.justsoftwaresolutions.co.uk/threading/acquiring-multiple-locks-without-deadlock.html
    QMutexLocker lock1(qMin(&rhs.m_mutex, &m_mutex));
    QMutexLocker lock2(qMax(&rhs.m_mutex, &m_mutex)); 
    m_foo = rhs.m_foo;
    m_bar = rhs.m_bar;
  }  
  void setFoo(int foo) {
    QMutexLocker lock(&m_mutex);
    m_foo = foo;
  }
  int foo() const {
    QMutexLocker lock(&m_mutex);
    return m_foo;
  }
  void setBar(bool bar) {
    QMutexLocker lock(&m_mutex);
    m_bar = bar;
  }
  bool bar() const {
    QMutexLocker lock(&m_mutex);
    return m_bar;
  }
};

All of the public methods are thread safe.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313