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.
Related
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;
};
The Code
I've been writing this c++ with Qt knowing it works but not really understanding why I sometimes do things other than "I just know I should be doing this".
This is my startup class which initialises my classes:
namespace GUI
{
Startup::Startup() :
QObject(nullptr),
m_setupTab(*new SetupTab(nullptr)),
m_regTab(*new CbcRegistersTab(nullptr)),
m_dataTab(*new DataTestTab(nullptr)),
m_mainView(*new MainView(nullptr,
m_setupTab,
m_regTab,
m_dataTab)),
m_systemController(*new SystemController(nullptr,
Provider::getSettingsAsSingleton())),
m_dataTest(*new DataTest(nullptr,
m_systemController)),
m_setupTabVm(new SetupTabViewManager(this,
m_setupTab,
m_systemController,
Provider::getSettingsAsSingleton() ))
{
}
Then in my header file the member variables are described as such:
private:
SetupTab& m_setupTab;
CbcRegistersTab& m_regTab;
DataTestTab& m_dataTab;
MainView& m_mainView;
Settings* m_settings;
SystemController& m_systemController;
DataTest& m_dataTest;
SetupTabViewManager* m_setupTabVm;
The main difference between the view manager and everything else is that view manager passes signals between the tab classes and everything else.
Then to start this in my main, all I do is this:
GUI::Startup startup;
startup.show();
SetupTabViewManager.cpp:
#include "setuptabviewmanager.h"
#include "View/setuptab.h"
#include "Model/systemcontroller.h"
#include "Model/settings.h"
#include <QDebug>
namespace GUI
{
SetupTabViewManager::SetupTabViewManager(QObject *parent,
SetupTab& tab,
SystemController& sysCtrl,
Settings& config) :
QObject(parent),
m_setupTab(tab),
m_systemController(sysCtrl)
{
WireMessages(config);
WireSetupTabButtons(config);
}
void SetupTabViewManager::WireMessages(Settings& config)
{
connect(&config, SIGNAL(notifyStatusMessage(QString)), //for QT4
&m_setupTab, SLOT(onStatusUpdate(QString)) );
connect(&m_systemController, SIGNAL(notifyStatusMessage(QString)),
&m_setupTab, SLOT(onStatusUpdate(QString)));
}
void SetupTabViewManager::WireSetupTabButtons(Settings& config)
{
connect(&m_setupTab, SIGNAL(onBtnLoadSettingsClicked(bool)),
&config, SLOT(onLoadButtonClicked(bool)) );
connect(&config, SIGNAL(setHwTree(QStandardItemModel*)),
&m_setupTab, SLOT(setHwTreeView(QStandardItemModel*)));
connect(&m_setupTab, SIGNAL(onBtnInitClicked()),
&m_systemController, SLOT(startInitialiseHw()));
connect(&m_setupTab, SIGNAL(onBtnCfgClicked()),
&m_systemController, SLOT(startConfigureHw()));
}
}
Questions
What is the advantage of initialising a class in a member variable as a pointer or a reference? I just know when I make a "view manager", I should initialise the member variable as a pointer. Though I'm not sure why?
Also what is the advantage of "this" or "nullptr" as the parent to the class?
Qt objects are organized in object trees. It allows a programmer not to care about destructing the created objects: they will be deleted automatically when their respective parents are deleted.
If you take a look at almost any Qt GUI application, then you will see that all of its widgets (buttons, checkboxes, panels, etc.) have one single ancestor - the main window. When you delete the main window, all your application widgets are automatically deleted.
You can set up this parent-child relation by passing a parent object to a newly created child:
QWidget *mainWidget = ...
QPushButton *btn = new QPushButton(mainWidget);
In this case, btn object becomes a child of the mainWidget object, and from this moment you may not delete that child manually.
If you create an object without a parent, you should always delete it by yourself.
As thuga mentioned in the comments, you can transfer object ownership later. Widgets can be places inside layouts and it will make them children of the layout owner. Or you can even explicitly set parent with QObject::setParent.
And as for declaring class members as pointers or references - it does not really matter. It's just a question of convenience.
In Qt world all child objects are getting deleted when their parent object is deleting. If you do not define class members (QObjects) as pointers, they will be deleted twice: once by their parent, and second time when your class object is destructed by itself, and this can lead to undefined behavior.
I've been running into problems with a C++ program that I've been working on recently. Specifically, I've been working on a program that uses Qt's GUI framework and I've been running into errors that seem to be related to double-deletion of pointers and exception handling. The issue is that I feel like the API that I'm using works in a way that isn't exactly predictable and because of that, I'm running into a lot of errors that seem counter-intuitive. I'm not the most experienced C++ programmer in the world, so maybe there is some overall strategy for working with new APIs that I'm missing..
Here's an example: I typically always try to delete objects that I dynamically allocate with inside the same class. In other words, if I populate a pointer using the new keyword within a class' constructor or init function, then I usually make sure to delete the contents of that pointer in the class' destructor.
Here's an simplified example of the class definition for the class that was giving me problems [MyProject.h]:
#ifndef MYPROJECT_H
#define MYPROJECT_H
#include "QObject.h"
class QGuiApplication;
class QQmlApplicationEngine;
#define MYPROJECT MyProject::getInstance()
class MyProject : public QObject
{
Q_OBJECT
private:
explicit MyProject(QObject *parent = 0); //singleton..
MyProject(MyProject const&); //uncopyable..
void operator=(MyProject const&); //unassignable..
QGuiApplication * QtGUI;
QQmlApplicationEngine * QmlAppEngine;
public:
~MyProject(void);
/* Globally available function to get MyProject's singleton instance.
* You can use the "MYPROJECT" preprocessor macro for shorthand. */
static MyProject & getInstance(void)
{
static MyProject instance;
return instance;
}
int init(int argc, char * argv[]);
int exec(void);
signals:
public slots:
};
#endif
This is what my simplified main.cpp looks like:
#include "MyProject.h"
int main(int argc, char * argv[])
{
MYPROJECT.init(argc, argv);
return MYPROJECT.exec();
}
Here's the ctor and init() that I initially had for that class [MyProject.cpp]:
MyProject::MyProject(QObject *parent) :
QObject(parent) ,
QtGUI(NULL) ,
QmlAppEngine(NULL)
{
}
MyProject::~MyProject(void)
{
//segfault: debug points to both of these..
if (QtGUI) delete QtGUI;
if (QmlAppEngine) delete QmlAppEngine;
}
int MyProject::init(int argc, char * argv[])
{
QtGUI = new QGuiApplication(argc, argv);
QmlAppEngine = new QQmlApplicationEngine();
if(QtGUI && QmlAppEngine)
{
//segfault: debug points to this..
QmlAppEngine->load(QUrl( QStringLiteral("qrc:///MyProject.qml") ));
}
else return 1;
}
int MyProject::exec(void)
{
return QtGUI->exec();
}
So, my plan was: ctor initializes pointers to NULL, init() populates those pointers with new objects, and if those pointers are not null the dtor cleans them up with delete. But this code crashes with 2 segfaults, but even though I think I've narrowed it down, I'm not sure I understand why they're both happening.
(1) Segfault #1 is a crash on startup that points to the "QmlAppEngine->load()" call inside the init(). I was able to prevent the crash from occurring by wrapping that function call in exception handling code like this:
int MyProject::init(int argc, char * argv[])
{
QtGUI = new QGuiApplication(argc, argv);
QmlAppEngine = new QQmlApplicationEngine();
if(QtGUI && QmlAppEngine)
{
//exception handling prevents crash..
try
{
QmlAppEngine->load(QUrl( QStringLiteral("qrc:///MyProject.qml") ));
}
catch(int e)
{
std::cout << "Exception: " << e << std::endl;
return 1;
}
return 0;
}
else return 1;
}
I'm not very familiar with exception handling, as most of the code I've written so far has used int return-code style error handling. I'm guessing that the load function can throw an exception in certain situations, and not handling them can cause a crash. The program stopped crashing on start-up once I made this change, but strangely, it didn't seem to actually throw an exception as my 'cout' never output anything.. Something else that I don't understand is that this code is called without any exception handling code in the default setup for brand new Qt Projects that Qt Creator makes - for example, this is what you see when you start a new QtQuick2 project in QtCreator IDE:
#include "QGuiApplication"
#include "QQmlApplicationEngine"
int main(int argc, char * argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine();
//default Qt file calls this without issue though..
engine.load(QUrl( QStringLiteral("qrc:///MyQml.qml") );
return app.exec();
}
The only major different that I can see here is that the default code uses objects instead of pointers to objects. But, in this case, load runs fine without exception handling code and there is no segfault..
(2) The next issue is caused when my dtor calls the delete keyword on those two pointers. If I comment out those two lines, the program runs fine and closes without crashes or issues. This leads me to believe that the API has made these objects delete themselves later, which is causing a segfault due to double-deletion when I also explicitly call delete. But, in general, how can one know if the API that they're using is taking care of object deletion internally? And, if I can't tell whether or not an API specified object is being deleted automatically, should I take any extra measures (i.e.: use some kind of smart pointer, etc.)? Typically I make the assumption that I should delete any dynamically allocated objects in the destructor of the same class, but clearly that can backfire in situations like this.
So what steps can I take to work with the APIs that I use in a way that (a) prevents bugs and (b) allows me to make sure that resources are being freed correctly and exceptions are being handled?
It's hard to find the exact location of error by seeing the sample code you provided, your application must have large code base and does many things with memory. Qt is a well designed and fully documented framework (though some documentation are misleading or outdated), I suggest you to read properly the documentation about a specific item if you have confusion. Here are some general issues I guess you should know/consider when using Qt:
When creating an object on the heap of class that inherits QObject, if you pass a parent ( another QObject) in the constructor, then the child object is owned by parent and memory will be freed automatically by the parent object.
QObject is NO_COPYABLE, so if you inherit from it, you don't need to make copy ctor/assignment operator private. The compiler generated versions of these methods calls parent version (here QObject), hence your class is automatically un-copyable/assignable.
new by default throws bad_alloc exception if it fails instead of returning NULL. So either you use try-catch or change default behavior by using no_throw version of new (new(std::nothrow)), it will return nullptr on failure.
deleteing a NULL pointer will not cause any problem. However, if the pointer points to arbitrary location / contain garbage value, deleteing it will result in segfault.
By default engine.load is not used with exception handler, so there is a high chance it does not raise exception. Look closely in other areas of your code.
I am making a client server application, with the server having a GUI. I am using Qt.
For communication I am using pipes.
I have divided the server application into a backend, and a GUI. The backend has a PipeServer class, and in the GUI, I have overriden functions like onReceiveMessage etc.
Everything worked fine until I decided to add a std::queue as a base class member.
At the start of the application, I get an exception, and upon inspection it seems that my queue does not start with 0 elements. In fact it seems like the queue is not initialized at all. There are 2 possibilites: it could be because I the GUI class inherits 2 classes, and somehow the second base class, which is my PipeServer does not properly initialize its members, or it could be because the pipeServerGUI object is moved to a different thread by QT.
Any ideas on how I could solve this?
Relevant code:
class HookServer
{
PIPEINST Pipe[INSTANCES];
HANDLE hEvents[INSTANCES];
VOID DisconnectAndReconnect(DWORD);
BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED);
VOID GetAnswerToRequest(LPPIPEINST);
public:
std::queue<std::string> messages;
int init(std::string pipename);
int run();
virtual void onNewConnection() {};
virtual void onReceiveMessage(std::string message) {};
};
class HookServerGUI : public QObject, public HookServer
{
Q_OBJECT
void onReceiveMessage(std::string message);
void onNewConnection();
public slots:
void doWork() {
init("\\\\.\\pipe\\hookpipe");
run();
}
signals:
void signalGUI(QString message);
};
//GUIServerCreation
QThread *thread = new QThread;
HookServerGUI* worker = new HookServerGUI;
QObject::connect(worker,SIGNAL(signalGUI(const QString&)),this,SLOT(processMessage(const QString&)));
worker->moveToThread(thread);
thread->start();
QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection);
EDIT:
The exception is a access violation exception. It happens in this part of code:
VOID HookServer::GetAnswerToRequest(LPPIPEINST pipe)
{
onReceiveMessage(pipe->chRequest);
if(!messages.empty())
{
std::string s = messages.front();
messages.pop();
strcpy(pipe->chReply,s.c_str());
pipe->cbToWrite = strlen(s.c_str()+1);
}
}
Since messages.empty() return some huge number, it tries to read the first object and somehow fails.
There is also no PipeServerGUI constructor.
EDIT2:
I solved part of this problem by placing parenthesis after new HookServerGUI();
The problem is that still the function does not work, and throws a access violation exception. It happens on the front() line. When checked in a debugger, the function does have 1 element, so it is not because it is empty. Any ideas?
EDIT3:
With the second run, unfortunately the queue.size() is still incorrect. Seems like a data race to me.
The problems are in the code that you don't show, and it's a classic case of a memory bug, it looks like. Some code somewhere is writing on memory it doesn't own. Probably you have a bug in the way you use winapi. You need to create a minimal, self-contained test case.
I think you might be shooting yourself in the foot by not using QLocalSocket: on Windows, it's a named pipe - exactly what you want.
Besides, this is C++ code. There is no reason at all to put either PIPEINST or HANDLE into a raw C array. Use QVector or std::vector. Probably the rest of the code is full of C-isms like that, and something somewhere goes wrong.
I wouldn't discount a buffer overrun, since obviously you are ignoring the size of the buffer in PIPEINST from the - the strcpy can overrun the buffer. I'm also not sure that PIPEINST from the example code is using the same character type as what std::string::c_str() is returning.
Even if you wanted to implement your code using explicit pipes without QLocalSocket, you should still use C++, QString etc. and understand what's going on with your data.
I was working for a while with different C++ GUI frameworks (e.g. Qt, wxWidgets, also some proprietary) but cannot decide for myself regarding the topic described below.
As discussed in several questions/answers here, direct use of delete this is valid in C++ (as long as you don't dereference this any more), but it is in most cases not good idea.
But in some cases, object invokes its destructor indirectly. This situation specifically often arise in event drive systems (GUI applications come to mind first).
class Kernel {
public:
void Start() {
_window = new Window();
}
void OnCloseButton() {
if (_window) {
_window->Close();
delete _window;
_window = NULL;
}
private:
MyWindow * _window;
};
class MyWindow
{
public:
MyWindow(Kernel & kernel) : _kernel(&kernel) {
Connect(my_button_close_event, this, OnCloseButtonClicked);
}
OnCloseButtonClicked() {
// This call actually calls destructor of this object.
_kernel->OnCloseButton();
// If we access any fields of Window here, we're going to have problems
}
private:
Kernel * _kernel;
};
Notice: I did not try to compile the code - it may have typos or bad practices. But it should illustrate the idea.
So, the question is: Is it OK to do something like in the example above: the handler of the event calls some other function (method of its owner), which indirectly deletes this?
Or should I better make the Kernel class event aware and connect the event from the button directly to the method in the Kernel and then we do not have this situation of indirect call to delete this.
Thanks in advance.
It's possible to do so since the Window instance is created by the Start() method but it's a bad practice in Object Oriented Programming.