在临时对象上创建 QListIterator?

Creating a QListIterator over a temporary object?

目前我正在做一些代码审查并偶然发现了以下结构:

QVariantMap argumentMap = QJsonDocument::fromJson(" ... JSON-String ... ", &error).toVariant().toMap();
...

QListIterator<QVariant> keyIterator( argumentMap["key"].toList() );

while ( keyIterator.hasNext() ) ...

我的第一感觉是这里的迭代器有问题,因为 toList() returns a QVariantList by value 导致一个临时对象。

所以 Ctor 被定义为 QListIterator(const QList<T> &list) 我们发现了这一点 [1]:“这是一个官方的 C++ 特性,可以将临时对象的生命周期延长到 const 引用的生命周期,它引用对它。”但首先我的论点是对列表的 const 引用的生命周期绑定到 Ctor。

所以我试图深入研究QListIterator的定义[2]:

Q_DECLARE_SEQUENTIAL_ITERATOR(List)

#define Q_DECLARE_SEQUENTIAL_ITERATOR(C) \
\
template <class T> \
class Q##C##Iterator \
{ \
    typedef typename Q##C<T>::const_iterator const_iterator; \
    Q##C<T> c; \
    const_iterator i; \
public: \
    inline Q##C##Iterator(const Q##C<T> &container) \
        : c(container), i(c.constBegin()) {} \

现在,我真的很困惑! :) 似乎对于 c 成员,迭代器拥有它自己的列表本地副本。所以最后,我想说这种用法是绝对有效的。有人可以确认一下吗?

此外,此构造在整个应用程序中使用,显然从未造成任何问题。

简短的附录:

我在这里也发现了这个 [3]:“如果你想使用 STL 迭代器迭代这些,你应该总是获取容器的副本并迭代副本。例如:”

// WRONG
QList<int>::const_iterator i;
for (i = splitter->sizes().begin(); i != splitter->sizes().end(); ++i)

首先我认为这是完全相同的问题,但转念一想我现在会说这里的问题是 begin()end() 上被调用不同份清单。正确吗?

[1] https://blog.galowicz.de/2016/03/23/const_reference_to_temporary_object/

[2]https://code.woboq.org/qt5/qtbase/src/corelib/tools/qiterator.h.html

[3]https://doc.qt.io/qt-5/containers.html#stl-style-iterators

QListIterator 应该没问题,因为它需要列表的副本。

你所指的临时对象的生命周期延长是这样的:

{
auto const & myRef = foo.bar();  // returns by value so it returns a temporary
// you would expect the temporary to be gone now
// and myRef thus being a dangling reference, but it is not!
myRef.doSomething();  // perfectly fine
}
// now that myRef is out of scope also the temporary is destroyed

有关生命周期的说明,请参阅 here

然而,这在这种情况下不相关,因为这种机制不能将临时对象的生命周期延长到 对象 的生命周期,而只能延长到 [=23] 的生命周期=]引用.

是的,最后一个例子是错误的,原因正是您给出的原因:将迭代器与不同的(临时)对象进行比较。