does it imply that QStateMachine::addState(QAbstractState * state)
must always be passed an dynamically allocated memory?
Not at all. The QState
is not special in any way, the same caveats apply to any QObject
. Recall that QObject
is a container for other QObject
s: it owns them, and unless they are separately destroyed first, will attempt to delete
child objects in QObject::~QObject
.
Your code can be fixed in several ways - in all cases, the objective is not to let the ~QObject
delete the child states it shouldn't be deleting.
It all gets really simple if you let the compiler do the job it's supposed to be doing. Your code style of using raw owning pointers and not initializing them at the point of definition is non-idiomatic and often inspires the bug you've run into. If you have an owning pointer, use std::unique_ptr
or QScopedPointer
. delete
and manual memory management belongs only within a single-purpose resource-managing class. It simply does not belong in general-purpose code: consider every explicit delete
to be a bug. You don't need them.
class CTestClass
{
public:
QState m_pTestState;
};
// Fix 1: Don't mix automatic storage duration with dynamic storage duration
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
{
QStateMachine TestStateMachine;
CTestClass TestClass;
TestStateMachine.addState(&TestClass.m_pTestState);
TestStateMachine.setInitialState(&TestClass.m_pTestState);
TestStateMachine.start();
TestStateMachine.stop();
} // <-- here the compiler emits
// TestClass.~TestClass()
// ...
// TestStateMachine.~QStateMachine()
// ...
// TestStateMachine.~QObject()
}
// Fix 2: Make sure that the child doesn't outlive the parent.
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
{
QScopedPointer<QStateMachine> TestStateMachine(new QStateMachine);
CTestClass TestClass;
TestStateMachine->addState(&TestClass.m_pTestState);
TestStateMachine->setInitialState(&TestClass.m_pTestState);
TestStateMachine->start();
TestStateMachine->stop();
} // <-- here the compiler emits
// TestClass.~TestClass()
// ...
// TestStateMachine.~QScopedPointer()
// delete data;
// data->~QStateMachine
// ...
// data->~QObject
// free(data)
}