Question

I always use below code to connect to a sqlite database. For some reasons, I have decided to rewrite it in a way that use *QSqlDatabase instead of QSqlDatabase.

What I did was just to use & in front of my old code ( Line_12 ). But the code crashes in line 6.

Anyway, someone gave me line_14 and It works.

So... I can't understand What was wrong with my first code and Why suggested code make it work.

Foo::Foo(QString path_="db_path_name") {
    InitialDataBase(path_);
    bool isOpened = db->open();
    if(!isOpened)   exit(1);
    else            
        queryExecutor = new QSqlQuery(*db);  // --> Line_6
}

void Foo::InitialDataBase(QString path_) {

    // Line_12 => DOESN'T WORK
    db = &(QSqlDatabase::addDatabase("QSQLITE"));   
    // Line_14 => WORK
    db  = new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE"));

    db->setHostName("localhost");
    db->setDatabaseName(path_);
    db->setUserName("admin");
    db->setPassword("admin");
}
Was it helpful?

Solution

In line 12, you're taking the address of the QSqlDatabase object returned by addDatabase(). That object is temporary and destroyed right away after the end of the statement (after line 12). So you end up with a dangling pointer, i.e. a pointer to an already deleted object. Dereferencing a dangling pointer is undefined behavior. In practice, it usually crashes.

In line 14, a new QSqlDatabase object is created on the heap, creating a copy of the temporary QSqlDatabase object returned from addDatabase(). The copy constructor QSqlDatabase(const QSqlDatabase&) is called here. The temporary object is destroyed, but the copy on the heap remains. Note that you have to delete db later, otherwise you end up with a memory and resource leak (open DB connection).

Why do you use a pointer here at all? Especially as a beginner, all it will result in is crashes and leaks, as this example demonstrates ;)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top