4

谁能解释一下,为什么下面的代码会根据复制 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;
    }

输出:

equality with copy: 0
equality without copy: 1

但是,无论复制如何,std::vector 都提供相同的输出。

Debian 7 x86 GCC x86 32 位 Qt 5.1.0 调试 qmake 规范 linux-g++

感谢您的回答

4

2 回答 2

4

发生这种情况是因为 QStringList 是 Qt 的隐式共享类之一,这意味着当您进行复制时,您实际上只是复制对列表内容的引用(“真正的”复制仅在/如果其中一个对象被修改时发生)。

如果你想像在这里一样进行迭代,你应该用 constEnd() 改变 end() 方法,就像这样:

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();

虽然 end() 方法返回一个迭代器,但 constEnd()(或 cend())返回一个 const_iterator,所以在这种情况下您需要使用它。如果您想更深入地调查,有一篇有趣的文章:

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

我希望这可以帮助你。

于 2013-07-25T06:42:52.623 回答
3
QStringList::const_iterator it = list.end();

对这个调用要非常小心——它会导致(可能是不需要的)分离。如果您不想要它,请使用 constEnd()。并防止进一步的问题,让我引用文档

隐式共享对 STL 风格的迭代器有另一个后果:当非常量迭代器在该容器上处于活动状态时,您不能获取容器的副本。Java 风格的迭代器不受此限制。

于 2013-07-25T07:43:26.823 回答