3

Is there any way to add & use a class in the QMap value?

I wanna use QMap<QString, Aclass> map; in Qt. and when I want to set it's value in a function, some errors appear:

C:\Qt\Qt5.5.0\5.5\mingw492_32\include\QtCore\qglobal.h:1043: error: 'QWidget& QWidget::operator=(const QWidget&)' is private
     Class &operator=(const Class &) Q_DECL_EQ_DELETE;
            ^

ps: my container class is inherited from QWidget & is singleton.

#include "Aclass.h"
#include <QWidget>

class AmainClass : public QWidget
{
    Q_OBJECT

public:
    static AmainClass &getInstance();
    void setApp(QString name, Aclass app);

private:
    AmainClass(QWidget *parent = 0);
    QMap<QString, Aclass> map;
};

and in .cpp:

void AmainClass::setApp(QString name, Aclass app)
{
    map.insert(name, app);
}

edit: Aclass is another class that is inherited from QWidget.

s.m
  • 209
  • 2
  • 7
  • 17

3 Answers3

2

All Qt Objects that are derivated from QObject cannot be copied, because the copy constructor is private. This is the error message. You could use a reference or a pointer to your object in the map

QMap<QString, Aclass&> map;

or

QMap<QString, Aclass*> map;

Then the set function should be

void setApp(QString name, Aclass& app){
map.insert(name, app);
}

When you use pointers just replace & with *

Liachtei
  • 512
  • 1
  • 4
  • 11
  • His `setApp` function has the same problem. – thuga Mar 09 '16 at 08:15
  • I try ` QMap map; ` --> error: no matching function for call to 'QMap::insert(QString&, Aclass*)' map.insert(name, &app); ^ – s.m Mar 09 '16 at 08:18
  • Yeah you should also adjust that. The best thing would be to change all signatures. I edit my solution – Liachtei Mar 09 '16 at 08:23
  • s.m. You must use either * or &. Do not mix them together. This is errorprone and in most cases do not work – Liachtei Mar 09 '16 at 08:28
  • @Liachtei i just tryed &. – s.m Mar 09 '16 at 08:33
  • 1
    but in your solution you wrote map.insert(name, &app); This is not valid. you can skip the & before app when your signature uses references. If you are confused with the &, you should check the c++ documentation for the difference between &, * and the smart pointers stated by the other guys – Liachtei Mar 09 '16 at 08:36
  • @Liachtei some errors appear: `C:\Qt\Qt5.5.0\5.5\mingw492_32\include\QtCore\qmap.h:416: error: forming pointer to reference type 'Aclass&' typedef T *pointer; ^` & `C:\Qt\Qt5.5.0\5.5\mingw492_32\include\QtCore\qglobal.h:1043: error: 'QWidget& QWidget::operator=(const QWidget&)' is private Class &operator=(const Class &) Q_DECL_EQ_DELETE; ^` & `C:\Qt\Qt5.5.0\5.5\mingw492_32\include\QtCore\qmap.h:260: error: the type being destroyed is 'Aclass', but the destructor refers to 'Aclass&' value.~T(); ^` – s.m Mar 09 '16 at 08:51
  • @s.m Perhaps you should use pointers in that case. i don't know the definition auf your Aclass, but there could be a hidden problem in that class. Try replacing all & with * and use raw pointers. Notice: that you then must explicitly allocate and deallocate the memory for the objects. – Liachtei Mar 09 '16 at 09:04
2

As per Qt documentation, QObject and classes derived from it do not support being copied: Qt's meta-object mechanism and similar infrastructure relies on pointers to QObjects remaining valid, which would not hold if they were copied or moved around. You therefore cannot store a QObject in a container by value. Use a smart pointer instead:

QMap<QString, std::unique_ptr<Aclass>> map;

The same applies to setApp as well, of course:

void AmainClass::setApp(QString name, std::unique_ptr<Aclass> app)
{
    map.insert(name, std::move(app));
}

Using a std::unique_ptr assumes three things:

  1. You are using a compiler which supports that part of C++11.
  2. Your version of Qt is recent enough to support move semantics.
  3. You intend map to be the sole owner of the Aclass objects.

Since this is 2016, 1 & 2 should really be true by now.

As for 3, you generally need to sort out ownership (a design decision) before you choose how to implement it (a coding decision). Based on your original example, I assume you want map to own the Aclass objects, hence my use of std::unique_ptr.

If you instead want to use a different ownership scheme (such as using Qt's parent-child ownership relationships), you'd use different storage. For the parent-child thing, a raw pointer (or perhaps QPointer) would be appropriate.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • your answer is something like @skypjack 's answer. I should develop std::unique_ptr in qt, shouldn't I? – s.m Mar 09 '16 at 08:32
  • This works as long as `app` is not a child of some other widget which could be destroyed before `AmainClass` instance. – thuga Mar 09 '16 at 08:34
  • @s.m What do you mean with "I should develop `std::unique_ptr` in qt"? `std::unique_ptr` is part of the standard library. Use it if your map is supposed to own the `Aclass` instance. If using a different form of ownership (such as Qt's parent-child relationships), use an appropriate pointer (such as `QPointer` or a raw pointer). – Angew is no longer proud of SO Mar 09 '16 at 08:35
  • @thuga Since the OP wanted to store the class by value, I consider it quite unlikely they want a different ownership scheme. – Angew is no longer proud of SO Mar 09 '16 at 08:36
  • It is hard to tell. Could be just lack of understanding of pointers and values in general. I mean storing a widget in a container by value makes no sense by itself. Also, it could be a dynamic UI where he might want to destroy some widget and replace it with another similar one. Destroying that widget before clearing the map would be disastrous. There are a lot of important details missing in the question. – thuga Mar 09 '16 at 08:41
  • @Angew because of this error: `error: 'std::unique_ptr' has not been declared void setApp(QString name, std::unique_ptr app);` ^ – s.m Mar 09 '16 at 08:42
  • @s.m `#include `. Anyway, it needs your version of Qt to support move semantics. If that's not the case, `std::shared_ptr` (same header) could be used instead. But please sort out the ownership first. I will expand the answer. – Angew is no longer proud of SO Mar 09 '16 at 08:46
  • @Angew It's `Qt Creator 3.4.2 (opensource)` , `Based on Qt 5.5.0 (MSVC 2013, 32 bit)` (on winows) . by the way I want to run my code on Qt4 either. – s.m Mar 09 '16 at 09:06
  • @s.m VS2013 supports `std::unique_ptr` just fine, and Qt 5.5 definitely supports move semantics. As for Qt 4 - consult the manual of the version you'd be using. – Angew is no longer proud of SO Mar 09 '16 at 09:09
  • @Angew I included `#include ` , `#include ` & `#include `, but error exists. – s.m Mar 09 '16 at 09:10
  • @s.m That looks like a separate issue, really. This question is about storing `QWidget`s in containers by value, and the answer is "Cannot be done. Use some sort of pointer instead." If you're having trouble storing a specific pointer type in a `QMap`, treat it as a new problem: search, and if you fail to find anything, ask a new question, this time including a real [mcve]. – Angew is no longer proud of SO Mar 09 '16 at 11:12
  • @Angew thanks for you suggestion. but which part of my question wasn't `Minimal, Complete, and Verifiable example` ? – s.m Mar 09 '16 at 11:14
  • @s.m For a question of this kind, an MCVE should be something I can copy-paste into a file (or two), compile, and observe the error myself. In your case, the definition of `Aclass` is missing altogether, as is (most likely) `#include `. – Angew is no longer proud of SO Mar 09 '16 at 11:33
  • Solved my problem. Also;- holy shit does C++ make me want to break things sometimes. – Shayne Feb 03 '19 at 08:45
0

You can use std::reference_wrapper<Aclass> as a type for value.
Be aware anyway that you must guarantee for the lifetime of the referenced objects. See the documentation for further details.

Otherwise, you can use smart pointers like std::unique_ptr<Aclass> or std::shared_ptr<Aclass>, so that lifetime will be automatically managed for you.
See here for further details about shared_ptr, here for unique_ptr.

Otherwise, far simpler, you can define the missed operator operator= for Aclass. How almost depends on your actual problem, I cannot even say if it's a viable solution.

skypjack
  • 49,335
  • 19
  • 95
  • 187
  • I'm not familiar with this. Can you explain more? – s.m Mar 09 '16 at 07:50
  • He cannot use the `operator=` as [`QObject` prohibits this](http://doc.qt.io/qt-5/qobject.html#no-copy-constructor-or-assignment-operator). – thuga Mar 09 '16 at 08:18