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.cppCode:
@
#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.
@ -
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.