Destructor(s) called twice as QList of objects derived from shared classes (such as QString) goes out of scope.



  • Platform: Qt5.1.0 (built as a shared library) / Linux Fedora 19 x64

    Hi everybody,

    I wanted to make sure destructors of classes derived from shared classes (such as QString and many more) are called when a QList of them is going out of scope. In this test program they happen to be...twice and I get this output (project file and test program code follow):

    Instantiating three DerivedFromQString classes and appending them to list

    Creating string: First string
    Destroying string: First string
    Creating string: Second string
    Destroying string: Second string
    Creating string: Third string
    Destroying string: Third string
    Destroying string: Third string
    Destroying string: Second string
    Destroying string: First string


    Project file:

    QT += core gui
    CONFIG += qt
    QT += widgets
    CONFIG += release
    TARGET = QList_Test
    TEMPLATE = app
    SOURCES = QList_Test.cpp

    Code:

    @
    #include <iostream>

    #include <QApplication>
    #include <QString>
    #include <QList>

    /*************************************************************************************************************/

    class DerivedFromQString:public QString
    {
    public:

    DerivedFromQString(const char *text):QString(text)
    {
    std::cout << "Creating string: " << text << std::endl;
    }

    ~DerivedFromQString() // Declaring the destructor as virtual does not change anything.
    {
    std::cout << "Destroying string: " << toStdString() << std::endl;
    }
    };

    /*************************************************************************************************************/

    int main(int argc, char **argv)
    {
    QApplication app(argc, argv);

    QList<DerivedFromQString> string_list;

    std::cout << "\nInstantiating three DerivedFromQString classes and appending them to list" << std::endl;

    string_list.append("First string");
    string_list.append("Second string");
    string_list.append("Third string");

    }// string_list goes out of scope. Destructors of its objects are unexpectedly called twice.
    @


  • Moderators

    That's correct behaviour, because you created two copies of each string.

    The first copy is created when your const char* input is converted into a DerivedFromQString using the constructor that you wrote. The second copy is created when QList::append() clones your value in order to store it, using the (default) copy constructor which doesn't print a message.

    If your compiler supports C++11, you can prevent the copying by specifying a move constructor. (According to "this":http://stackoverflow.com/questions/4819936/why-no-default-move-assignment-move-constructor, you don't get a default move constructor because you specified a non-default destructor.) However, even if you don't have C++11, the copying is still cheap since QString is implicitly shared (a.k.a. copy-on-write).

    [quote]Creating string: First string
    Destroying string: First string
    Creating string: Second string[/quote]Notice that the destructor is called BEFORE the constructor for "Second string" -- The first copy of "First string" went out of scope when string_list.append("First string") returned.

    By the way, instead of std::cout, you can use qDebug()



  • Thanks for your enlightening comments.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.