我怎样才能 return 一个 QList<specificObject*> 指针并且没有内存泄漏?

How can I return a QList<specificObject*> pointer and get no memory leak?

我的数据库中有一个问题和一个答案 table。这两者之间的关系是一个问题可以有多个答案。在我的 C++ 代码中,我有一个 Question 普通对象,它存储问题文本和一个 QList 答案。 Answer 普通对象只存储答案文本。

我想阅读所有问题以及与这些问题相关的所有答案,并将它们存储在我的问题对象中。这就是我所做的。

QList<Question*> *ExamPersistance::readQuestions(int examId)
{
    QList<Question*> *questions;
    QSqlQuery *query = new QSqlQuery(connection->getDb());
    query->prepare("select q.id, q.text from question q where id_exam =:examId");
    query->bindValue(":examId",examId);
    query->exec();
    while(query->next())
    {
        questions->append(new Question(
                             query->value(1).toString(),
                                       this->readAnswers(query->value(0).toInt())));
    }
    return questions;
}

QList<Answer*> *ExamPersistance::readAnswers(int questionId)
{
    QList<Answer*> *answers;
    QSqlQuery *query = new QSqlQuery(connection->getDb());
    query->prepare("select a.text from answer a where id_question = :questionId");
    query->bindValue(":questionId",questionId);
    query->exec();
    while(query->next())
    {
        answers->append(new Answer(query->value(0).toString()));
    }
    return answers;
}

我遇到分段错误,我不知道为什么。

这些是我的头文件中的构造函数

 Answer(QString text);
 Question(QString name, QList<Answer*> *answers);

也许我对指针做错了什么。我不得不承认我不是很熟悉这些因为我来自 Java.

编辑:

我还有一个 class "exam",它存储了某个考试的问题,但我认为这不重要。只是你知道这个 "int examId" 代表什么

您忘记初始化一些指针。

修复了崩溃和内存泄漏的版本:

QList<std::unique_ptr<Question>> ExamPersistance::readQuestions(int examId)
{
    QList<std::unique_ptr<Question>> questions;
    QSqlQuery query(connection->getDb());
    query.prepare("select q.id, q.text from question q where id_exam =:examId");
    query.bindValue(":examId",examId);
    query.exec();
    while(query.next())
    {
        questions.append(std::make_unique<Question>(
                             query.value(1).toString(),
                                       this->readAnswers(query.value(0).toInt())));
    }
    return questions;
}

How can I return a QList pointer and get no memory leak?

最简单且可能是最佳的方法是存储值而不是指针:

QList<Question> listOfQuestions;
QList<Answer> listOfAnswers;

此外,我们还可以制作共享指针的集合。但这不是那些在 QSharedPointer 上阅读的内容的预期用途。

QList<QSharedPointer<Question>> listOfQuestions;
QList<QSharedPointer<Answer>> listOfAnswers;

否则你需要弄清楚哪个对象负责释放你作为指针传递给列表的对象(通过提供 'parent' 指针非常流行的 Qt 技术)。

实际值列表:

QList<Question> ExamPersistance::readQuestions(int examId)
{
    QList<Question> questions;
    QSqlQuery query(connection->getDb());
    query.prepare("select q.id, q.text from question q where id_exam =:examId");
    query.bindValue(":examId",examId);
    query.exec();
    while(query.next())
    {
        questions.append(Question(
                             query.value(1).toString(),
                                       this->readAnswers(query.value(0).toInt())));
    }
    return questions;

}

QList<Answer> ExamPersistance::readAnswers(int questionId)
{
    QList<Answer> answers;
    QSqlQuery query(connection->getDb());
    query.prepare("select a.text from answer a where id_question = :questionId");
    query.bindValue(":questionId",questionId);
    query.exec();
    while(query.next())
    {
        answers.append(Answer(query.value(0).toString()));
    }
    return answers;
}

当然要注意你的问题中看不到的实际构造函数参数。使用 C++ 11 和 'move' 构造函数应该非常有效。

您正在解除对 QList 指针的引用,但您从未对它们进行初始化(即它们指向垃圾)。此代码应该可以解决该问题。

QList<Question*> *ExamPersistance::readQuestions(int examId)
{
    QList<Question*> *questions = new QList<Question*>();
    QSqlQuery *query = new QSqlQuery(connection->getDb());
    query->prepare("select q.id, q.text from question q where id_exam =:examId");
    query->bindValue(":examId",examId);
    query->exec();
    while(query->next())
    {
        questions->append(new Question(
                             query->value(1).toString(),
                                       this->readAnswers(query->value(0).toInt())));
        }
        return questions;

    }

QList<Answer*> *ExamPersistance::readAnswers(int questionId)
{
    QList<Answer*> *answers = new QList<Answer*>();
    QSqlQuery *query = new QSqlQuery(connection->getDb());
    query->prepare("select a.text from answer a where id_question = :questionId");
    query->bindValue(":questionId",questionId);
    query->exec();
    while(query->next())
    {
        answers->append(new Answer(query->value(0).toString()));
    }
   return answers;

}

请注意,这只是我发现的问题。即使此代码运行,它也存在其他问题。您肯定会泄漏与变量 query 关联的内存,并且可能会泄漏所有 Questions 和 Answer 对象(以及我们正在处理的 QList)的内存,除非您稍后在某个时候删除它们。在 C++ 中,每次调用 new 时都需要调用 delete,否则会泄漏内存。除非您确实需要,否则在 C++ 中通常不赞成使用指针。这与必须使用 new 来创建对象的 Java 有很大不同。 answer 对 C++ 中 new 运算符和 Java 的区别进行了不错的讨论,是一个很好的起点。