Now, I perfect my question.The pointer m_Core will be initialized and GetCore() will be called first for sure.The most I concerned is the document said root component will be deleted automatically when QPluginLoader is fully unloaded,and I don't know how Qt process the memory when Qt destruct QPluginloader and instances. If Qt will delete the Object before the destruction of QPluginLoader, I don't need to free it manually. In fact, when I invalid the delete m_Core, Qt reports no err, if I valid it, Qt will report segment fault, so Qt must destruct Mplugin class before call ~Mplugin() function.
The m_Core is derived class of QWidget:
SF_Core.h
#include <QWidget>
class SF_Core:public QWidget
{
SF_Core(QWidget* parent):QWidget(parent){}
~SF_Core(){}
};
and I use it through QPluginLoader in my project like this:
mainWindow.h
#include "MInterface.h"
#include "SF_Core.h"
#include <QWidget>
class MainWindow:public QWidget
{
Q_Object
MainWindow();
~MainWindow();
private:
MInterface* interface;
QObject* plugin;
MCore* core;
}
mainWindow.cpp
void mainWindow::mainWindow()
{
QPluginLoader loader("SF_Core.dll");
plugin = loader.instance();
interface = qobject_cast<MInterface* >(plugin);
core = interface->GetCore();
}
I have a plugin class derived from MIngerface class in Qt program, and override the function GetCore() in MIngerface.
#include "SF_Core.h"
class Mplugin:public QObject,MInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID INTERFACE_ID)
Q_INTERFACES(MInterface)
public:
Mplugin();
~Mplugin(){
delete m_Core;
}
SF_Core* GetCore(){
m_Core = new SF_Core;
return m_Core;
}
private:
SF_Core* m_Core;
};
In main program, I load the plugin by QPluginLoader,and use instance() to get the root component. When I terminated the program, it crashed.I found the err came from the sentence delete m_Core; If I don't delete m_Core, will it cause memory leak?
Initial short answer
Keeping in mind the principle of ownership, most probably yes: it will cause memory leak.
Also, consider that each call to GetCore will allocate a new instance and create memory leak.
However, without having a full example, it is difficult to understand how SF_Core is used, especially if it ownership is transferred or not.
Stack variable fix
What if you use an internal stack value? (Not the best practice, however to publish internal properties)
SF_Core* GetCore()
{
return &m_Core;
}
private:
SF_Core m_Core;
Alternative using shared_ptr
An alternative is to use smart pointer (which I highly recommend over raw pointers whenever possible):
using SfCorePtr = std::shared_ptr<SF_Core>;
SfCorePtr GetCore()
{
if (!m_CorePtr)
{
m_CorePtr = std::make_shared<SF_Core>(); // Lazy creation
}
return m_CorePtr;
}
private:
SfCorePtr m_Core;
Hint: to be even more pedantic, the use of std::weak_ptr allows to give access to a smart pointer without providing it ownership: If GetCore return a weak_ptr, the ownership of m_Core is keep inside this object and the ownership stay in a tree-shape instead of graph-shape.
Minimal fix
Otherwise, just fixing your code:
#include "Mcore.h"
class Mplugin:public QObject,MInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID INTERFACE_ID)
Q_INTERFACES(MInterface)
public:
Mplugin();
virtual ~Mplugin(){
delete m_Core;
}
SF_Core* GetCore(){
if (nullptr == m_Core){
m_Core = new SF_Core;
}
return m_Core;
}
private:
SF_Core* m_Core=nullptr;
};
Related
For example, I have code that I often see:
class SomeClass : public QObject
{
Q_OBJECT
public:
QHash *parameterTable;
explicit ExCurrentSession(QObject *parent = nullptr);
};
SomeClass::SomeClass(QObject *parent) : QObject(parent)
{
parameterTable = new QHash;//used dynamic creation
QFile file("someFile.txt");//Creating an object on the stack
if (!file.open(QIODevice::ReadOnly|QIODevice::WriteOnly))
QTextStream fileSream(&file);//Creating an object on the stack
QString buff = fileSream.readLine();//Creating an object on the stack
//...Other code to set the QHash table with a parameter and a value from a file...
}
The question is whether there will be memory leaks after exiting the method:
-QFile file ? I have no idea what's inside there using dynamic memory, maybe it's not used there.And if it`s using in another subclass inside this class.
-QTextStream fileSream ?I have no idea what's inside object using dynamic memory or not, maybe it's not used there.And if it`s using in another subclass inside this class.
-QString buff?I have no idea what's inside object using dynamic memory or not, maybe it's not used there.
I don’t understand how to determine whether it is possible to use an object on a stack (method / function) if you did not write it yourself and do not 100% sure that dynamic memory allocation is not used there.
Maybe it is more correct? But why often write as in the first version.
SomeClass::SomeClass(QObject *parent) : QObject(parent)
{
parameterTable = new QHash;//used dynamic creation
QFile *file = new QFile("someFile.txt");//Creating an object on the stack
if (!file->open(QIODevice::ReadOnly|QIODevice::WriteOnly))
QTextStream *fileSream = new QTextStream(file);//Creating an object on the stack
QString *buff = fileSream->readLine();//Creating an object on the stack
//...Other code to set the QHash table with a parameter and a value from a file...
delete file;
delete fileSream;
delete buff;
}
For "someHash" the destructor is invoked automatically as well?
class SomeClass : public QObject
{
Q_OBJECT
public:
QHash<QString,QString> someHash;
};
I know that this question is probably opinion oriented, but since I am an amateur programmer I want to know whether this is a good practice to clean up the memory.
To clear my objects I use static QVector in which I store the pointers to the objects created and I made a static function called Perfrom_Cleanup which deletes all the objects from the pointers stored in the vector. Here is my code, to get a clearer idea.
Header File
#ifndef AUTOMATIC_CLEANUP_H
#define AUTOMATIC_CLEANUP_H
#include <QObject>
#include <QVector>
#include <QDebug>
class Automatic_Cleanup : public QObject
{
Q_OBJECT
static QVector<Automatic_Cleanup*> m_Objects;
public:
explicit Automatic_Cleanup(QObject *parent = nullptr);
~Automatic_Cleanup();
static void Perfrom_Cleanup();
signals:
public slots:
};
#endif // AUTOMATIC_CLEANUP_H
CPP File
#include "Automatic_Cleanup.h"
QVector<Automatic_Cleanup*> Automatic_Cleanup::m_Objects;
Automatic_Cleanup::Automatic_Cleanup(QObject *parent) : QObject(parent)
{
m_Objects.append(this);
}
Automatic_Cleanup::~Automatic_Cleanup()
{
qDebug()<<"Deleting object "<<this->objectName();
int i = m_Objects.indexOf(this, 0);
if(i<0)
return;
m_Objects.remove(i);
}
void Automatic_Cleanup::Perfrom_Cleanup()
{
// Deleting from last
for(int i=m_Objects.count()-1; i>=0; i--){
Automatic_Cleanup *obj = m_Objects.at(i);
delete obj;
}
}
From my main cpp file I am doing this, to verify
for(int i=0; i<10; i++){
Automatic_Cleanup *obj = new Automatic_Cleanup;
obj->setObjectName(tr("Object %1").arg(i+1));
if(i==4)
delete obj;
}
Automatic_Cleanup::Perfrom_Cleanup();
In Qt memory management is organized by parent-child relation.
Basically when you create a new QObject of any kind, and give it a parent argument, parent will be responsible for deleting that object.
So basically, this static vector is obsolete and this is not an opinion.
When parent-child relation is used if you delete root element all children will be destroyed.
This static vector is kind of global variable and this should be avoided in any framework or programming language. So this is another reason not to use it.
This approach has too many downsides, many of them have been already mentioned.
I would like to additionally note that you are only cleaning up your memory at the end of your main function (most modern operating systems clean up anyway when your process exits*).
A more serious need for this clean-up emerges while running your program, for instance, when your program has allocated too many objects and still needs more (e.g. imagine that you are writing a service that should run for weeks or maybe months). Your approach wouldn't be of any help in this case.
You are basically implementing a garbage collector that kicks in only when the program is about to exit, and works for a specific hierarchy of types.
* please note that I am not encouraging the delegation of any form of clean-up from the process to the operating system.
I have run into an issue of the most simple kind that I cannot seem to resolve.
I have a class called UI, inside UI.h I am storing a single variable called index, and have a method setup(), which sets the value of index:
class UI {
public:
float index;
public:
void setup(float p_selectedMicrobeIndex);
};
With the implementation of setup being:
void UI::setup(float p_selectedMicrobeIndex)
{
microbeIndex = p_selectedMicrobeIndex;
}
Inside my game class .h file I am declaring an instance of a class called UI:
#include "UI.h"
class Game {
private:
UI* ui;
};
Inside Game.cpp I am running UI.setup() to set the value of index.
ui->setup(0.0f);
I am struggling to understand why this results in a segmentation error.
Any help would be appreciated. Thanks.
You are creating a pointer, but you don't create an instance for it to point to. You should either create an intance
UI ui;
ui.setup(0.0f);
or do so with a pointer (although I don't see why)
UI* ui = new UI;
ui->setup(0.0f);
such that the pointer actually points to something sensible.
UI* ui; just reserves memory for the pointer to an object of UI but no memory for the UI object. Thus, the setup fails, because you try to write to not allocated memory.
I made a widget (QDataflowCanvas) based on QGraphicsView, where I connect the signal QGraphicsScene::selectionChanged() to the slot MainWindow::onSelectionChanged of my main window:
void MainWindow::onSelectionChanged()
{
// canvas is ptr to QDataflowCanvas, subclass of QGraphicsView
auto selNodes = canvas->selectedNodes();
auto selConns = canvas->selectedConnections();
...
}
The problem happens when I close my MainWindow and there is some item selected in the QGraphicsView.
I don't think I need to provide the complete code (although it can be found here), as I already isolated the cause of the crash.
This is what will happen (in order of causality):
destructor of MainWindow is called
destructor of QDataflowCanvas is called
destructor of QGraphicsView is called
destructor of QGraphicsScene is called, which triggers the removal of all items (with clear())
destructor of a QGraphicsItem is called
that will trigger a selectionChange event
the MainWindow::onSelectionChanged slot is called
method QDataflowCanvas::selectedNodes() is called, but the object is destroyed
crash!
which can be seen more in detail from the stack trace of the crash:
I found this workaround: if I disconnect the signal in MainWindow::~MainWindow, it will of course not crash:
MainWindow::~MainWindow()
{
QObject::disconnect(canvas->scene(), &QGraphicsScene::selectionChanged, this, &MainWindow::onSelectionChanged);
}
But this seems a rather atypical practice: I never found myself having to manually severe signal-slot connections because the program would otherwise crash.
There must be a more proper solution to this.
First of all, the name of your project is a mistake. The Q-prefixed namespace is taken. You should not be having any Q-prefixed classes in any project that uses Qt. You should rename the project to DataflowCanvas, for example.
There are three solutions:
Hold all children by value, order the children according to their dependencies. The QWidgetPrivate::deleteChildren called from QDataFlowCanvas will be a no-op, or at least it won't be touching objects you care about.
Use the old connect syntax when connecting to the MainWindow::onSelectionChanged slot. Note that when your slot was invoked, the mainwindow object was of the QWidget dynamic type, not MainWindow type. The connections made using the old connect syntax respect the dynamic type of the object, and a connection made to a slot of given class will guarantee that the object is of that class dynamically, i.e. at runtime.
Clear the selection in the destructor - then no futher selection changes will be handled.
The first solution makes everything explicit and is the one I'd use:
class DataFlowCanvas : public QGraphicsView {
...
private:
QDataflowModel *model_;
QDataflowTextCompletion *completion_;
QSet<QDataflowNode*> ownedNodes_;
QSet<QDataflowConnection*> ownedConnections_;
QMap<QDataflowModelNode*, QDataflowNode*> nodes_;
QMap<QDataflowModelConnection*, QDataflowConnection*> connections_;
bool showIOletsTooltips_;
bool showObjectHoverFeedback_;
bool showConnectionHoverFeedback_;
qreal gridSize_;
bool drawGrid_;
QGraphicsSecene scene_;
};
The scene is destructed before any other fields. Problem solved. You should hold everything else by value as well. E.g. completion_, etc. The pointer indirections are not useful.
The second solution highlights an unfortunate Qt bug. To wit -- in the code below, the old connect syntax will never invoke Derived2::aSlot2, because at the time the slot is invoked, the object isn't of the Derived2 type anymore:
#include <QtCore>
int ctr1, ctr2;
struct Derived1 : QObject {
Q_SLOT void aSlot1() { ctr1++; qDebug() << __FUNCTION__; }
Q_SIGNAL void aSignal();
~Derived1() { Q_EMIT aSignal(); }
Q_OBJECT
};
struct Derived2 : Derived1 {
Q_SLOT void aSlot2() { ctr2++; qDebug() << __FUNCTION__ << qobject_cast<Derived2*>(this); }
Q_OBJECT
};
int main() {
{
Derived2 d;
QObject::connect(&d, &Derived2::aSignal, &d, &Derived2::aSlot2);
QObject::connect(&d, SIGNAL(aSignal()), &d, SLOT(aSlot2()));
QObject::connect(&d, SIGNAL(aSignal()), &d, SLOT(aSlot1()));
}
Q_ASSERT(ctr1 == 1);
Q_ASSERT(ctr2 == 1);
}
#include "main.moc"
The output clearly demonstrates the problem:
aSlot2 QObject(0x0) <-- aSlot2 called but `this` is of `Derived1*` type!
aSlot1
I was taking it so simple :) What about just checking canvas pointer:
void MainWindow::onSelectionChanged()
{
if (!qobject_cast<QGraphicsScene*>(canvas))
return;
auto selNodes = canvas->selectedNodes();
auto selConns = canvas->selectedConnections();
...
}
I used qobject_cast to check if pointer canvas still exists. You can check in other (better) way. The code works.
I have an application that opens a QDialog for some flow, and when it is closed, the QMainWindow is opened.
In the QDialog I create some objects that I'd like to pass as a pointer (or some other way) to the QMainWindow. For example I create a SysTray object that needs to change its state from the QMainWindow. What is the best way? Singletons?
update .
after implementing the sulotion another question was rises , does the QDialog is cleaned from memory that means , invoked its destructor ? i don't think its the case . i have to do some object cleaning , and there destructor never invoked
One approach is to allocate on the heap with the QMainWindow as a parent. The QObject-hierarchy will take care of freeing the memory and you will access the object for the lifetime of the QMainWindow.
If at any point you know for sure that you don't need the QDialog or the shared object anymore, you can call deleteLater.
Example:
class MyDialog : public QDialog
{
Q_OBJECT
QObject* _objToShare;
public:
QObject* objToShare() const { return _objToShare; }
MyDialog(QObject* parent = 0) : QDialog(parent)
{
_objToShare = new QObject(this); // either use this as the parent
// or free by hand in the destructor
}
// ...
};
class MyWindow : public QMainWindow
{
Q_OBJECT
// ...
QObject* ptrToSharedObj; // alternatively you can hold a pointer
// to your MyDialog instance
};
Where you use your QDialog:
MyDialog* d = new MyDialog(this);
d->exec();
ptrToSharedObj = d->objToShare();
// don't delete d explicitly, the QObject hierarchy will take care of that
A better (and likely more memory-friendly) approach is to use a shared pointer implementation. Qt has a variety of smart pointer classes, one of which is QSharedPointer. It is basically a thread-safe, reference-counted pointer which means that if you grab one that points to the shared object of your QDialog, it will not get freed as long as there are any other QSharedPointers pointing to it. Keep in mind that this might cause circular references if you are not careful.
Example:
class MyDialog : public QDialog
{
Q_OBJECT
QSharedPointer<QObject> _objToShare;
// ^ don't delete in the destructor
public:
QSharedPointer<QObject> objToShare() const { return _objToShare; }
MyDialog(QObject* parent = 0) : QDialog(parent)
{
_objToShare = QSharedPointer<QObject>(new QObject);
// no parent to avoid destruction when the dialog is destructed
}
// ...
};
class MyWindow : public QMainWindow
{
Q_OBJECT
// ...
QSharedPointer<QObject> ptrToSharedObj;
};
Where you use your QDialog:
MyDialog d;
d.exec();
ptrToSharedObj = d.objToShare();
From this point on, even if d goes out of scope (i.e. destroyed), you will still have a valid pointer to the shared data (well, of course unless you do something explicitly to invalidate it).
You have a lot of different options. Some of these may not be applicable to your situation:
Case 1: Caller knows best (i.e. procedural programming)
Define a controller that can control the ordering. That control can then act as the intermediary and get the data once the dialog has closed:
void FlowController::displayFlow()
{
MyDialog *dialog = new MyDialog();
YourSharedData *data = NULL;
int result = dialog->exec();
if (result == QDialog::Accepted) {
data = dialog->sharedDataAccessor();
}
MyMainWindow *window = new MyMainWindow();
window->setSharedData(data);
window->exec();
}
Case 2: Message Passing
Create both the dialog and the main window up front. Connect the corresponding signals and slots and let them both be ignorant of one another. This is usually much easier to test and keep decoupled:
void AppLauncher::launch()
{
MyDialog *dialog = new MyDialog();
MyMainWindow *window = new MyMainWindow();
window->connect(
dialog,
SIGNAL(dialogResult(int, const SharedData&)),
SLOT(setDialogResult(int,const SharedData&))
);
}
void MyMainWindow::setDialogResult(int result, const SharedData& sharedData)
{
if (result == Dialog::Accepted) // something domain-specific would be better
{
this->processSharedData(sharedData); // do whatever with it.
}
}
Case 3: Shared State Dependency
Define your shared data up front and make it a dependency for each form. Each form then defines state, acts based on that state, or some combination of both:
void AppLauncher::launch()
{
SharedData *data = this->createSharedData();
MyDialog *dialog = new MyDialog(data);
MyMainWindow *window = new MyMainWindow();
dialog->exec(); // does what it needs with shared data
window->exec(); // checks shared data and acts accordingly
}
Case 4: MVC / MVP / MVVM
You may be able to define your shared state as a model that they both act upon. This may not be much different than case three above.
Case 4: Singleton or global state
It will work, but please don't do it :).
In QDialog you have owner, which is probably QMainWindow. (if not, you may add it there, ore get parent objects until you come to QMainWindow class). You may refer to it when creating new objects...
You can subclass QApplication to have it keep a pointer to your systray object, or other objects which should be available "application wide".
In a Qt application, there is only a single instance of QApplication, available everywhere using the qApp macro.
See this mailing list discussion which also contains an example.