【问题标题】:Qt's foreach expression requires a deep copy?Qt的foreach表达式需要深拷贝?
【发布时间】:2013-01-14 11:21:09
【问题描述】:

Qt 的 foreach 函数有点问题。我有一个类 Phrase,它是 QList 的子类。在 ~Phrase 中,我删除了所有 GlossItem 指针。

在遍历 Phrase 中的 GlossItem 指针时,我想使用 Qt 的 foreach:

    // phrase is a pointer to a Phrase object, 
    // which is a subclassed QList<GlossItem*>
    foreach( GlossItem *glossItem , *phrase )
    {
        // use glossItem
    }

由于某种原因,foreach 正在对 Phrase 执行深层复制(我知道这一点,因为它需要我实现复制构造函数)。但是如果有 Phrase 的副本——并且我不想创建每个 GlossItem 的深层副本——这意味着这些指针将被删除两次。 (或者,删除一次,然后崩溃。)所以我必须使用这个,它有效但不太漂亮。

    for(int i=0; i<phrase->count(); i++ )
    {
        GlossItem *glossItem = phrase->at(i);
        // use glossItem
    }

有没有办法解决这个问题,还是我只需要忍受它?

【问题讨论】:

  • 在你的第一个例子中,你使用了一个索引变量i——它在哪里适合?
  • 另外,我没有看到任何证据表明QList 有一个虚拟析构函数,它允许您从中继承。
  • 这不是一个好的设计:容器是用来复制的,在 dtor 中删除它的内容会破坏(使用 Q_DISABLE_COPY 来防止复制)。正如 Tony 所说,QList 没有虚拟 dtor,因此继承它不是一个好主意。设计提示:永远不要从容器继承,而是让它们成为某个包装类的成员。类短语 { QList list() const; ... Q_DISABLE_COPY(短语) };
  • 该索引变量是复制/粘贴错误,组件 10,我对其进行了编辑。感谢您的设计投入,弗兰克。当我第一次编写代码时,我怀疑继承 QList,但现在我有一个具体的理由不这样做。

标签: c++ qt foreach


【解决方案1】:

来自文档

Qt 在进入 foreach 循环时自动获取容器的副本。

由于 foreach 创建了容器的副本,因此对变量使用非常量引用不允许您修改原始容器。

所以我认为foreach 不适合您的特定用例,否则您最终会得到带有附加指针的Phrase 的新副本,而不是返回您想要的实际原始Phrase

【讨论】:

  • 我从来没有意识到这一点——乍一看,这是一种可怕的实现 foreach 的方式。为什么巨魔做出这个决定?如果迭代器被要求是一个 const ref,那么人们将有机会注意到这种意外行为,但它的实现方式,直到您迭代默认复制构造函数不能复制的内容时,您才会注意到。
【解决方案2】:

不,如果您查看从 foreach 扩展的代码:qt.gitorious.org/qt/qt/blobs/HEAD/src/corelib/global/qglobal.h#line2371 它使用 const_iterator。是的,它确实复制了容器,但是由于 Qt 中的所有容器类都是隐式共享的,所以它只是浅拷贝,而不是深拷贝。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-12
    • 1970-01-01
    相关资源
    最近更新 更多