【问题标题】:Creating a QListIterator over a temporary object?在临时对象上创建 QListIterator?
【发布时间】: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&lt;T&gt; &amp;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


【解决方案1】:

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

但是在这种情况下这并不相关,因为这种机制不能将临时对象的生命周期延长到 object 的生命周期,而只能延长到 reference 的生命周期.

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-30
    • 2014-06-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-25
    相关资源
    最近更新 更多