在临时对象上创建 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] 的生命周期=]引用.
是的,最后一个例子是错误的,原因正是您给出的原因:将迭代器与不同的(临时)对象进行比较。
目前我正在做一些代码审查并偶然发现了以下结构:
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] 的生命周期=]引用.
是的,最后一个例子是错误的,原因正是您给出的原因:将迭代器与不同的(临时)对象进行比较。