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.
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 *
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:
You are using a compiler which supports that part of C++11.
Your version of Qt is recent enough to support move semantics.
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.
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.
Related
I'm trying to store references to objects that inherit from a nested abstract base class inside a std::set in the outer class.
Let me show you the code first since I think that's much more clear:
Class.h interface:
#ifndef Class_H_
#define Class_H_
#include <set>
#include <memory>
class Class
{
public:
class AbstractBase;
private:
std::set< std::shared_ptr<AbstractBase>> set;
public:
Class();
~Class();
void add(AbstractBase& object);
};
#endif
Abstract.h interface:
#ifndef ABSTRACT_H_
#define ABSTRACT_H_
#include "Class.h"
class Class::AbstractBase
{
friend class Class;
public:
virtual ~AbstractBase();
private:
virtual void foo(int in) = 0;
};
#endif
Derived.h interface:
#ifndef DERIVED_H_
#define DERIVED_H_
#include "Class.h"
#include "AbstractBase.h"
class Derived : private Class::AbstractBase
{
public:
~Derived() override;
private:
void foo(int in) override;
};
#endif
add.cc implementation:
#include "Class.h"
#include "AbstractBase.h"
void Class::add(AbstractBase& object)
{
// create a shared pointer to object
// and insert it in the set
set.insert(std::make_shared<AbstractBase>(object)); // <-- this is where it fails
}
So I would have multiple different derived objects all inheriting from AbstractBase which need to be stored together in the std::set container.
Compilation fails because of the pure virtual function. At first, I didn't use the std::shared_ptr and thought that this was the reason for failure, I found this SO answer suggesting to use a std::shared_ptr instead. I'm still getting a compilation error in Class::add because AbstractBase::foo is pure, but I thought the std::shared_ptr would solve this?
I found similar questions but nothing that helped me solve my specific problem. Could someone explain to me what I'm doing wrong?
Thank you.
EDIT: Wow! Thanks for the informative answers, I'll need some time to thoroughly understand them all and see what works best for me. I'll update this question once I'm done!
What your function attempts to do is make a copy of an object, allocate a shared instance for the copy, and store pointer to the copy.
Since your intention is to "store references" in the set, you presumably intend to store the objects elsewhere and don't actually want copies. If those referred objects are shared, then the correct solution is to pass the shared pointer:
void Class::add(std::shared_ptr<AbstractBase> ptr)
{
set.insert(std::move(ptr));
}
If the referred objects aren't shared, then you cannot refer to them with a shared pointer. You can use a non-owning pointer instead:
std::set<AbstractBase*> set;
void Class::add(AbstractBase* ptr);
However, be very careful with the non-owning approach to keep the referred objects alive at least as long as they are referred by the set. This is non-trivial. Reference can be used as an argument to add, but I recommend against this, since it may not be obvious to the caller that the function will store pointer to the argument for longer than the functions execution.
If you do want to copy, then you can use a virtual function that returns a shared pointer. Example:
class Class::AbstractBase
{
public:
virtual std::shared_ptr<AbstractBase> copy() = 0;
// ...
class Derived : private Class::AbstractBase
{
public:
std::shared_ptr<AbstractBase> copy() override {
auto ptr = std::make_shared<Derived>(*this);
return {ptr, static_cast<Class::AbstractBase*>(ptr.get())};
}
// ...
void Class::add(AbstractBase& object)
{
set.insert(object.copy());
To avoid repeating the identical copy in multiple derived types, you can use CRTP.
If you want to copy a class of unknown dynamic type, there are three well-known ways to get around having insufficient information:
Have a way to map the object to a handler expecting that specific most-derived type. typeid, a member-function, or a data-member in the common base-class which is its static type is most often used. This costs time, and is cumbersome to set up, but at least you often don't have to modify the class or use fat pointers.
Have a function to .clone() the object in the statically known base. This is known as the virtual constructor idiom, and generally the most efficient and convenient to set up.
Lug around an extra-pointer for cloning. This is the least invasive to the type or regarding additional setup, but changes the interfaces.
Which is most appropriate is yours to decide.
That is, if you actually want to copy the object, and shouldn't have passed a shared_ptr to .add() instead.
You need to clarify the ownership of the objects stored in the set. If you use std::shared_ptr, you fundamentally encode that the set inside each Class owns the contained instances. This is incompatible with an add(AbstractBase&) method - you cannot really take ownership of an arbitrary object by reference. What if this object is already managed by a different shared_ptr?
Maybe you actually only want to store copies in the set. In that case, see the other answer(s) for ways to polymorphically copy ("clone") objects.
It is also open why you want to use std::set. std::set establishes uniqueness of the contained objects using the < operator (or a user-provided comparison functor with equivalent semantics). Do you even want uniqueness? If so, based on what criteria? Currently, there is no way to compare the stored class objects. std::shared_ptr "solves" that problem by instead comparing the internal pointer values, but I doubt that's what you need here.
If you actually want to store and compare objects solely based on their memory locations and not assume ownership of the stored objects, you could just use raw pointers. If you only want to store a whole bunch of objects without caring about uniqueness (since you currently attempt to create copies, each stored element would have a unique address and thus you currently would never use that aspect of std::set), maybe std::vector is the better solution. std::set may also help with determining whether an object is present in the collection efficiently, but std::vector can do that just the same (and possibly faster, if you sort and binary search). Consider the advice in http://lafstern.org/matt/col1.pdf.
A lot of the examples for using std::unique_ptr to manage ownership of class dependencies look like the following:
class Parent
{
public:
Parent(Child&& child) :
_child(std::make_unique<Child>(std::move(child))){}
private:
std::unique_ptr<Child> _child;
};
My question is whether marking the _child member as const have any unexpected side effects? (Aside from being ensuring that reset(), release() etc. cannot be called on _child).
I ask since I have not yet seen it in an example and don't whether that is intentional or just for brevity/generality.
Because of the nature of a std::unique_ptr(sole ownership of an object) it's required to have no copy constructor whatsoever. The move constructor(6) only takes non-const rvalue-references which means that if you'd try to make your _child const and move it you'd get a nice compilation error :)
Even if a custom unique_ptr would take a const rvalue-reference it would be impossible to implement.
The downsides are like with any const member: That the assignment and move-assignment operators don't work right (they would require you to overwrite _child) and that moving from the parent would not steal the _child (performance bug). Also it is uncommon to write code like this, possibly confusing people.
The gain is marginal because _child is private and therefore can only be accessed from inside the Parent, so the amount of code that can break invariants revolving around changing _child is limited to member functions and friends which need to be able to maintain invariants anyways.
I cannot imagine a situation where the gain would outweigh the downsides, but if you do you can certainly do it your way without breakage of other parts of the program.
Yes, you can do this, and it's what I regularly do when implementing UI classes in Qt:
namespace Ui {
class MyWidget
}
class MyWidget : public QWidget
{
Q_OBJECT
const std::unique_ptr<Ui::MyWidget> ui;
public:
explicit MyWidgetQWidget *parent = 0)
: ui(new Ui::MyWidget{})
{
}
~MyWidgetQWidget();
// destructor defined as = default in implementation file,
// where Ui::MyWidget is complete
}
It's exactly comparable to writing Ui::MyWidget *const ui in C++03 code.
The above code creates a new object, but there's no reason not to pass one in using std::move() as in the question.
I wanted to create a QObservableCollection wrapper around a QList(using an internal QList for implementation and forwarding all calls while emiting some sort of CollectionsChanged signal for functions that change the collection), but I see that QList does not inherit from QObject.
I believe you need to inherit from QObject to emit Qt Signals. So I'd need to inherit from QObject for my QObeservableCollection.
But QList and QVector and the other Qt collections doen't inherit from QObject, so I imagine their must be some sort of downside or problem making a collection.
I see that QSignalSpy inherits from both QObject and QList<QList<QVariant>> so maybe they just didn't see a reason to inherit from QObject?
There is a very important technical reason: The moc cannot handle templates, which is pretty much a necessity for a generic container type.
QList is meant to be a value type (like std::vector) which uses implicit sharing while QObjects must be used as pointers and disallow copying
there are other classes which mirror this use such as QImage
Reason is simple containers are like values, you have assign operator, you can copy them clone and so on.
QObjects can't have such functionality, they are not copyable. Try imagine what should happen when you creating clone of object with connected slots and signals. It will lead to total mess. And what should happen with children of cloned object? Should be also cloned?
Another thing is templates usage. Class template which is a QObject is real problem for moc a tool.
It is certainly not true that you need to be a QObject to emit signals. All you need is there to be a QObject somewhere that emits the signals for you. If you want your class to be directly passable to QObject::connect, your class should provide a conversion operator to QObject* that returns the pointer to such a proxy object. This completely sidesteps the whole no-templates-with-moc brouhaha.
class FrobinatorObject : public QObject {
Q_OBJECT
Q_SIGNAL void frobSignal();
...
};
template <typename T> class Frobinator {
QScopedPointer<FrobinatorObject> m_proxy;
// Could be a QSharedPointer, depending on what semantics we want
...
public:
operator FrobinatorObject*() const { return m_proxy.data(); }
};
...
Frobinator<int> frob;
QObject::connect(frob, SIGNAL(frobSignal()), ...);
// or
QObject::connect(frob, &FrobinatorObject::frobSignal, ...);
Also note that while it's true that you can't have signals nor slots in a template-parametrized class, you can certainly have them in a base class that you then derive from. The base class can deal with type-deleted arguments. So:
// This won't work
template <typename T> class TemplateClass : public QObject {
Q_OBJECT
Q_SLOT void aSlot(const T *);
...
};
// But this certainly does work
class BaseClass : public QObject {
Q_OBJECT
Q_SLOT void aSlot(const void *);
...
}
template <typename T> class TemplateClass : public BaseClass {
void aMethod(const T * t) {
BaseClass::aSlot((const void*)&t);
}
...
}
The TemplateClass can also dynamically add slots of the correct type signature to the BaseClass. While that requires some understanding of Qt's internals, it can certainly be done for a class that's supposed to be a reusable, framework-style class.
While I can't look into the minds of the developers, I would say that there's simply no need. A QList is a simple container. It should hold elements, allow for their addition or removal, iteration over them, etc.
It does not need a parent or children. There's no immediate need for signals or slots. It's a matter of keeping things simple.
If you do indeed require additional functionality beyond what a QList provides, it's easy enough to implement. But as for a general case, I guess it's a reasonable and logical decision to not overcomplicate things.
The extra overhead in inheriting from QObject is unnecessary for the majority of uses. Containers should be as small and as fast as possible.
If you wanted to inherit from QList and provide that functionality for a class of your own, you can do that.
Here is my issue.
I'm creating my own GUI Api. All the Widgets are in a container which has add and remove functions. The widgets derive from a base widget class. Here is where I'm unsure. I would ideally like a flow like this:
user creates a (desired widget deriving from base class) pointer, the container allocates and manages resources, the user has a pointer to the widget and can make calls to it.
However, polymorphism makes this confusing. How could I get my container to create the right type of new? The issue here is that anyone can create a new widget (like SuperTextBoxWidget) which is why supplying a string and doing a switch would not solve this.
My other quick-fix alternative is to make the user responsible for doing the new, and providing the pointer to the container's add function. But this does not feel idiot proof to me, and it seems odd to have the user do the initial allocation, but then the container manages the rest including erasure.
What would be the best and cleanest way to go about this?
Thanks
just an idea of what I have so far:
class AguiWidgetContainer
{
std::vector<AguiWidgetBase*> widgets;
public:
AguiWidgetContainer(void);
~AguiWidgetContainer(void);
void handleEvent(ALLEGRO_EVENT* event);
int add(AguiWidgetBase *widget);
bool remove(int widgetId);
};
I can think of at least two ways to do this.
1. Provide a template version of add:
template<class T>
int add() {
widgets.push_back(new T);
}
2. Use a factory class:
You can have a base factory class that defines methods to allocate (and possibly also free) widgets. Your users then provide their own subclass of the factory that creates the correct type of widget. For example:
class AguiWidgetFactory {
AguiWidgetBase *createWidget() = 0;
};
class AguiSuperWidgetFactory : public AguiWidgetFactory {
AguiWidgetBase *createWidget() {
return new SuperTextBoxWidget();
}
};
Your add method then takes a factory object as input and uses it to create a new widget.
I would suggest borrowing from COM and making your base widget class a pure virtual interface which includes a function to destroy itself. Then implementers of your widget don't even all have to use the same allocator (important if you ever cross DLL boundaries).
EDIT: Example:
class IWidget
{
public:
virtual Size Measure() = 0;
virtual void Draw(Point) = 0;
//and so on
virtual void Release() = 0;
};
class TextBoxWidget : public IWidget
{
TextBoxWidget() {}
~TextBoxWidget() {}
public:
// implement IWidget functions, etc, etc
static TextBoxWidget* Create() { return new TextBoxWidget(); }
virtual void Release() { delete this; }
};
Now TextBoxWidget can only be created with TextBoxWidget::Create() and released with someTBW->Release(), and always uses new and delete inside the same DLL, guaranteeing that they match.
My other quick-fix alternative is to
make the user responsible for doing
the new, and providing the pointer to
the container's add function. But this
does not feel idiot proof to me, and
it seems odd to have the user do the
initial allocation, but then the
container manages the rest including
erasure.
Why does it feel odd to you?
If a container starts taking responsibility of allocating the objects to be contained, it violats SRP. I would recommend that you design your interfaces to accept pointers to Widget objects that are allocated by users. The container is only responsible for containing/storing/retreiving them.
The user also takes responsibility of deleting the allocated objects.
Most of STL containers work in this way.
I have a mother class that stores the pointers to some objects in a list. I want these objects to detach themselves from the list when they are destroyed.
Can anyone suggest some good ways to do this please?
The crude way is to store the container reference (or pointer) in the objects in the list and remove themselves in their destructors:
class Contained;
class Container {
std::list<Contained*> children;
public:
...
void goodbye(Contained*);
};
class Contained {
Container& c; // you set this in the constructor
public:
~Contained() { c.goodbye(this); }
};
Note that this makes the Contained class non-copyable.
The easy way is to use some framework that already provides such functionality. Eg. if you use Qt, you would just derive the Contained class from QObject and store QPointer<Contained> in the Container. The QPointer would be set to zero once the contained object is deleted.
Or, if you use some memory management facilities like boost::shared_pointer, (I assume the Container doesn't own the Contained objects, otherwise, it knows best when the child object dies), you would use a weak pointer in the Container, which has similar functionality.
you can add reference/pointer to the mother class in those classes and when destructor is called they call mother.Detach(this)