QStates的内存管理添加到QStateMachine

时间:2015-10-13 17:28:52

标签: c++ qt state state-machine

以下代码会因内存损坏而导致崩溃。我假设是因为delete pTestStateMachine试图删除未在堆中分配的内存。这是对的吗?

如果是这样,是否意味着QStateMachine::addState(QAbstractState * state)必须始终传递动态分配的内存?不幸的是Qt docs doesen没有指定任何此类条件。我在这里缺少什么?

class CTestClass
{
public:
    QState m_pTestState;
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QStateMachine *pTestStateMachine;
    CTestClass  TestClass;

    pTestStateMachine = new QStateMachine();
    pTestStateMachine->addState(&(TestClass.m_pTestState));
    pTestStateMachine->setInitialState(&(TestClass.m_pTestState));
    pTestStateMachine->start();

    pTestStateMachine->stop();
    delete pTestStateMachine;

    return a.exec();
}

2 个答案:

答案 0 :(得分:6)

  

是否意味着QStateMachine::addState(QAbstractState * state)必须始终传递动态分配的内存?

完全没有。 QState在任何情况下都不是特殊的,相同的警告适用于任何QObject。回想一下,QObject是其他QObject的容器:它拥有它们,除非它们先被单独销毁,否则将尝试在deleteQObject::~QObject个子对象。

您的代码可以通过多种方式修复 - 在所有情况下,目标都不是让~QObject删除不应删除的子状态。

如果你让编译器完成它应该做的工作,那一切都变得非常简单。使用原始拥有指针而不是在定义时初始化它们的代码风格是非惯用的,并且经常激发您遇到的错误。如果您拥有自己的指针,请使用std::unique_ptrQScopedPointerdelete和手动内存管理仅属于单用途资源管理类。它根本不属于通用代码:将每个显式delete都视为错误。你不需要它们。

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)
}

答案 1 :(得分:3)

来自文档的措辞

  

如果状态已经在另一台计算机上,它将首先从旧计算机中删除,然后添加到此计算机中。

QStateMachine取得QState的所有权,这意味着它会尝试删除它在破坏时拥有的所有状态,您可以传递动态分配的指针,也可以使用QStateMachine::removeState() }:

  

从此状态机中删除给定状态。状态机释放了该州的所有权。

所以这应该有效:

class CTestClass
{
public:
    QState m_pTestState;
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QStateMachine *pTestStateMachine;
    CTestClass  TestClass;

    pTestStateMachine = new QStateMachine();
    pTestStateMachine->addState(&(TestClass.m_pTestState));
    pTestStateMachine->setInitialState(&(TestClass.m_pTestState));
    pTestStateMachine->start();

    pTestStateMachine->stop();
    pTestStateMachine->removeState(&(TestClass.m_pTestState)); //removing state before deletion
    delete pTestStateMachine;

    return a.exec();
}