Reputation: 139
I have a classic QDialog which populates a QTreeView with a QFileSystemModel and has a function to filter and process the list of user-selected items. I'm a total C++ and Qt newbie, so I've been following numerous online tutorials and examples. The code ends up looking something like this [content anonymized and edited for brevity]:
In the header file:
class MyExampleDialog : public QDialog
{
Q_OBJECT
public:
explicit MyExampleDialog(MyMainWidget *parent = nullptr);
~MyExampleDialog();
public slots:
virtual void accept() override;
private slots:
void directoryPathEntered();
void checkDirectoryPathAndUpdateTree(const QString& pathToCheck);
void validateSelection();
private:
QString getDirectoryPath() const;
QStringList updateFileSelection();
Ui::MyExampleDialog *_ui;
};
and in the source file:
MyExampleDialog::MyExampleDialog(MyMainWidget *parent) :
QDialog(parent),
_ui(new Ui::MyExampleDialog)
{
_ui->setupUi(this);
_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
_ui->directoryPathEdit->setText(getDirectoryPath());
checkDirectoryPathAndUpdateTree(getDirectoryPath());
QObject::connect(_ui->browseButton, &QPushButton::pressed, this, &MyExampleDialog::directoryPathEntered);
QObject::connect(_ui->directoryPathEdit, &QLineEdit::textChanged, this, &MyExampleDialog::checkDirectoryPathAndUpdateTree);
}
MyExampleDialog::~MyExampleDialog()
{
delete _ui;
}
void MyExampleDialog::directoryPathEntered()
{
const QString currentPath = getDirectoryPath();
QString newPath = QFileDialog::getExistingDirectory(this, tr("Select the installation directory"), currentPath);
if(newPath.isEmpty())
return;
_ui->directoryPathEdit->setText(newPath);
// then write newPath to QSettings
}
QString MyExampleDialog::getDirectoryPath() const
{
// retrieve path from QSettings
}
void MyExampleDialog::checkDirectoryPathAndUpdateTree(const QString& pathCheck)
{
if(std::filesystem::exists(pathCheck.toStdString()+"/bin/config.xml"))
{
QStringList filters;
filters << "*.jpeg";
QFileSystemModel *model = new QFileSystemModel(this);
model->setRootPath(pathCheck+QString::fromUtf8("/Images"));
model->setReadOnly(true);
model->setFilter(QDir::AllDirs | QDir::AllEntries | QDir::NoDotAndDotDot);
model->setNameFilters(filters);
_ui->imgTreeView->setModel(model);
_ui->imgTreeView->setRootIndex(model->setRootPath("/Images"));
_ui->imgTreeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
QObject::connect(_ui->imgTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MyExampleDialog::updateImgSelection);
QObject::connect(_ui->imgTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MyExampleDialog::validateSelection);
}
else
{
if(pathCheck.isEmpty()) { }
else
{
QMessageBox::critical(this, tr("Error"), tr("No config.xml file in installation /bin directory"));
}
_ui->imgTreeView->setModel(nullptr);
}
}
QStringList MyExampleDialog::updateImgSelection()
{
QItemSelectionModel *selModel = _ui->imgTreeView->selectionModel();
QModelIndexList selIndices = selModel->selectedIndexes();
QStringList imgSel;
QFileSystemModel *fsModel = static_cast<QFileSystemModel*>(_ui->imgTreeView->model());
foreach(QModelIndex index, selIndices)
{
// parse data to obtain file name
}
return imgSel;
}
void MyExampleDialog::validateSelection()
{
QStringList imgList = updateImgSelection();
if(! imgList.isEmpty())
{
_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
}
else { _ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); }
}
void MyExampleDialog::accept()
{
// do stuff when OK is clicked
}
Note that in the function checkDirectoryPathAndUpdateTree
, we declare a pointer to a new QFileSystemModel object using new
. This pointer cannot be removed with delete
in the scope of this function because I want the model to persist so that updateImgSelection
can use it. This seems to be pretty standard use of QFileSystemModel objects, but in C++ we are taught never to instantiate an object with new
without subsequently using delete
to deallocate the memory. My question is whether this usage of QFileSystemModel causes a memory leak, and if so how to avoid it?
Upvotes: 1
Views: 217
Reputation: 904
Welcome to the fun-derful world of C++ and Qt. You are right in being cautious about pairing up a 'new' with a 'delete' somewhere down the line. However, Qt's engine does a lot of object management for you.
The short answer: this will not cause a memory leak
The longer short answer: This will not cause a memory leak. You are creating an object and telling Qt that the parent of this object is 'this'. Qt now has your object in a parent child relationship with 'this' being the parent and your new object being the child. When the parent is deleted the child will be deleted right along with it.
However, please do yourself a favor and take the time to learn about how Qt handles objects and when it is up to you to take care of the instance. If you don't you may find yourself with very frustrating memory leaks, seemingly random crashes, or "losing" objects you think should exist.
Good luck and keep at it.
Upvotes: 2