Search code examples
c++sqlqtpointersqlist

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


I have a question and a answer table in my database. The relation between those two is that a question can have multiple answers. In my C++ code I have A Question plain object, which stores the question text and a QList of answers. The Answer plain object just stores the answer text.

I want to read all questions and all answers related to these questions and store them in my question object. this is what I did.

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

I am getting segmentation fault and I don't know why.

These are my constructors in my header files

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

Maybe I am doing something wrong with the pointers. I have to admit I am not very familiar with these as I came from Java.

EDIT:

I have also a class "exam" which stores questions to a certain exam but I didn't consider this important to mention. Just that you know what this "int examId" stands for


Solution

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

    The easiest and likely the optimal way would be to store values and not pointers:

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

    Also, we can make the collection of shared pointers. But that is not an intended use of those so read on QSharedPointer.

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

    Otherwise you need to figure out what object is responsible for releasing the object you pass to list as pointer (very popular Qt techniques by providing the 'parent' pointer).

    List of values in practice:

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

    Of course mind the actual constructor parameters which is not seen from your question. With C++ 11 and 'move' constructors in use that should be very efficient.