I have the following code:
#include <QApplication>
#include <memory>
#include <QUndoCommand>
#include <QWidget>
class Document
{
public:
Document()
{
qDebug("Document");
}
~Document()
{
qDebug("~Document");
}
QUndoStack mUndostack;
};
class DocumentRepository
{
public:
DocumentRepository()
{
qDebug("DocumentRepository");
}
~DocumentRepository()
{
qDebug("~DocumentRepository");
}
void AddDoc(std::shared_ptr<Document> doc)
{
mDocs.emplace_back(doc);
}
std::vector<std::shared_ptr<Document>> mDocs;
};
class Gui : public QWidget
{
public:
Gui(DocumentRepository& repo)
: mRepo(repo)
{
qDebug("+Gui");
for(int i=0; i<3; i++)
{
CreateDoc();
}
mRepo.mDocs.clear();
qDebug("-Gui");
}
~Gui()
{
qDebug("~Gui");
}
void CreateDoc()
{
auto docPtr = std::make_shared<Document>();
connect(&docPtr->mUndostack, &QUndoStack::cleanChanged, this, [=](bool clean)
{
// Using docPtr here causes a memory leak on the shared_ptr's, the destruct after ~Gui
// but without using docPtr here they destruct before ~Gui as exepected.
QString msg = "cleanChanged doc undo count " + QString::number(docPtr->mUndostack.count());
qDebug(msg.toLatin1());
}, Qt::QueuedConnection);
mRepo.AddDoc(docPtr);
}
DocumentRepository& mRepo;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
DocumentRepository repo;
Gui g(repo);
g.show();
return 0;
}
Which outputs:
DocumentRepository
+Gui
Document
Document
Document
-Gui
~Gui
~Document
~Document
~Document
~DocumentRepository
But here you can see that the Document
instances are leaked as they are destructing after the Gui
instance. If you take a look at the comments you'll see I narrowed this issue down to the signal's lambda using the shared_ptr
. I want to know why does this cause a leak and how can it be resolved?
For reference the "correct"/non leaking output when not using the shared_ptr
in the lambda is:
DocumentRepository
+Gui
Document
Document
Document
~Document
~Document
~Document
-Gui
~Gui
~DocumentRepository