Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QStringList iterator's end seems invalid after copying

Tags:

qt

qt5

Could anyone explain me, why the following code produces different results depending on copying QStringList:

    #include <stdio.h>
    #include <QStringList>

    bool qtTest(bool b)
    {
        QStringList list;
        list.push_back("0");
        list.push_back("1");
        list.push_back("2");

        QStringList::const_iterator it = list.end();

        if (b) {
            // 'static' to prevent optimization
            static QStringList copy = list;
        }

        --it; // 2
        --it; // 1
        --it; // 0
        ++it; // 1
        ++it; // 2
        --it; // 1
        ++it; // 2
        ++it; // end

        return it == list.end();
    }

    int main(int, char *[])
    {
        printf("equality with copy: %d", qtTest(true));
        printf("equality without copy: %d", qtTest(false));

        return 0;
    }

Output:

equality with copy: 0
equality without copy: 1

However, std::vector provides equal output regardless of copying.

Debian 7 x86 GCC x86 32 bit Qt 5.1.0 debug qmake spec linux-g++

Thanks for answers

like image 699
yudjin Avatar asked Mar 24 '23 01:03

yudjin


2 Answers

That happens because QStringList is one of Qt's implicit shared classes, that means that when you do the copy you're actually only copying a reference to the list contents (the "real" copying happens only when/if one of the objects is being modified).

If you want to iterate like you're doing here, you should change the end() method with constEnd(), just like this:

QStringList::const_iterator it = list.constEnd();

if (b) {
    // 'static' to prevent optimization
    static QStringList copy = list;
}

--it; // 2
--it; // 1
--it; // 0
++it; // 1
++it; // 2
--it; // 1
++it; // 2
++it; // end

return it == list.constEnd();

While end() method returns an iterator, constEnd() (or cend()) returns a const_iterator, so that's what you need to use in this case. There's an interesting article if you want to investigate deeper:

http://doc.qt.digia.com/qq/qq12-qt4-iterators.html#implicitsharinganditerators

I hope that this can help you.

like image 154
pragmanomos Avatar answered Apr 07 '23 07:04

pragmanomos


QStringList::const_iterator it = list.end();

Be very careful about this call -- it will cause a (maybe unwanted) detach. Use constEnd() if you don't want it. And preventing a further question, let me quote the docs:

Implicit sharing has another consequence on STL-style iterators: You must not take a copy of a container while non-const iterators are active on that container. Java-style iterators don't suffer from that limitation.

like image 31
peppe Avatar answered Apr 07 '23 07:04

peppe