5

This really feels like a bug in Qt. Anyone has a solution or should I file it as a bug?

#include <QReadWriteLock>

class FileInfoWrapper {

public:
    explicit FileInfoWrapper(const QFileInfo& _fileInfo);
    ~FileInfoWrapper();

private: // also tried public
    mutable QReadWriteLock lock_;

Before even using it, I get the error:

Error 1 error C2248: 'QReadWriteLock::QReadWriteLock' : cannot access private member declared in class 'QReadWriteLock'

Doesn't matter if it's private/public or what classes I include. I don't seem to be able to create it on the stack. Instead I created one on the heap using 'new', but when I try to delete it in the constructor my application crashes with:

Unhandled exception at 0x5090f39a (QtCored4.dll) in MyApp.exe: 0xC0000005: Access violation reading location 0xfeeeff0e.

Call stack:

QtCored4.dll!QHash::~QHash() Line 283 + 0xa bytes C++ QtCored4.dll!QReadWriteLockPrivate::~QReadWriteLockPrivate() + 0x38 bytes C++ QtCored4.dll!QReadWriteLockPrivate::`scalar deleting destructor'() + 0xf bytes C++ QtCored4.dll!QReadWriteLock::~QReadWriteLock() Line 137 + 0x1e bytes C++ CloudSync.exe!FileInfoWrapper::~FileInfoWrapper() Line 76 + 0x15 bytes C++

The variable 'd' in QReadWriteLockPrivate seems to be deleted twice. However, this works in another class where I also had to create the lock on the heap and then delete it in the constructor.

Running Qt 4.8.0 in Visual Studio. Had the same issue in Qt creator 4.7.4.

chikuba
  • 4,229
  • 6
  • 43
  • 75

1 Answers1

6

You have to use a pointer because QReadWriteLock is not copyable (it uses Q_DISABLE_COPY) and you are somehow copying your FileInfoWrapper objects (by storing them in a container for example).
So the pointer address is shared between those copies, and deleted once for each copy.

You can wrap the pointer inside a smart pointer, so that deletion will only occur when the last copy of your object is deleted.

QSharedPointer<QReadWriteLock> lock_;
alexisdm
  • 29,448
  • 6
  • 64
  • 99
  • So no need for deletion of it in the fileWrappers constructor? And yes, I have a list of these files, but I still don't fallow. Will I in theory only have one lock that all of the objects share? And if I have a class that I only will have one of and want to declare this on the stack, can I use the Q_DISABLE_COPY macro in my class then? – chikuba Mar 01 '12 at 00:05
  • **1.** Yes, you won't need to delete it explicitly in the destructor anymore. **2.** The locks will be shared between copies of the same `FileInfoWrapper` objects, if you create 2 `FileInfoWrapper` objects from scratch (though your constructor taking a QFileInfo`), there will be 2 independent locks. **3.** If you mean allowing only one instance of a class for the whole application, you should try a "singleton pattern" instead. – alexisdm Mar 01 '12 at 01:20
  • I never copy the FileInfoWrapper, just have a lot of instances of the object. But do you mean if I have one of the object outside the list? Doesn't make sense – chikuba Mar 01 '12 at 02:51
  • And why can I never create QRWL on the stack? It always complains – chikuba Mar 01 '12 at 02:56
  • When you create an object on the stack and put it in a QList, it is copied at least once. – alexisdm Mar 01 '12 at 03:19
  • and how do you create it as mutable so my const functions can use it? – chikuba Mar 01 '12 at 21:49
  • 1
    also, now when they are all pointing to the same locker "lock_ = QSharedPointer(new QReadWriteLock);", (this might sound stupid), but will I be able to read OR write to the different objects in a list seperatly? Even though they share the same lock? And will this pointer really point to the same object? Feels like I'm creating a new lock in every copy of the fileWrapper – chikuba Mar 01 '12 at 21:58
  • **1.** As with a regular pointer, the part that is protected by the const is the pointer address, not the pointee object, so you can access any non const members of the QReadWriteLock without having them declared as mutable inside a const FileInfoWrapper. **2.** Since you don't explicitly copy your objects, except when you are first inserting objects in the list, you can consider that `QSharedPointer` is a regular `QRWL *` pointer. In your case, QSharedPointer will only prevent the double delete and won't change anything else in the behavior of your code. – alexisdm Mar 01 '12 at 22:47