【发布时间】:2022-01-06 12:59:32
【问题描述】:
目前我正在做一些代码审查,偶然发现了以下结构:
QVariantMap argumentMap = QJsonDocument::fromJson(" ... JSON-String ... ", &error).toVariant().toMap();
...
QListIterator<QVariant> keyIterator( argumentMap["key"].toList() );
while ( keyIterator.hasNext() ) ...
我的第一感觉是这里的迭代器有问题,因为toList() 按值返回了QVariantList,从而导致了一个临时对象。
因此,Ctor 被定义为QListIterator(const QList<T> &list),我们发现这个 [1]:“将临时对象的生命周期延长到引用它的 const 引用的生命周期是官方的 C++ 功能。”但首先我的论点是,对列表的 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
【问题讨论】:
-
由于迭代器类内部有一个副本,一切都很好。
标签: c++ qt iterator temporary-objects