Qt5.7的deleteLater()是否依赖于操作系统?

时间:2017-05-15 18:21:25

标签: c++ windows qt qt5

大家好,我在代码中发现了一个错误,即:

我有一个指向QLocalSocket的指针列表,在析构函数中我使用以下代码关闭并删除它们

for ( int i = 0; i < localSocketsList.size(); i++ )
{
    if ( localSocketsList.at(i) != NULL )
    {
        localSocketsList.at(i)->close();
        localSocketsList.at(i)->deleteLater();
    }
}

该错误是我之前使用套接字的disconnected()信号连接了一个插槽,并且插槽也删除了它们以及代码:

QMutableListIterator<QLocalSocket *> iterator(localSocketsList);
while( iterator.hasNext() )
{
    QLocalSocket * currentLocalSocket = iterator.next();
    if ( currentLocalSocket -> state() == QLocalSocket::UnconnectedState )
    {
        currentLocalSocket -> deleteLater();
        iterator.remove();
    }
}

好了,现在你可以看到错误,我尝试删除两次指针,然后发生了崩溃。但是,我花了一段时间来检测此错误,因为我没有在Windows 10中观察到崩溃,仅在Windows 7中。

问题是:Qt5.7的deleteLater()功能是否存在一些差异,具体取决于操作系统?不应该在所有平台上出现此问题,因为它是c ++运行时错误吗?

可能取决于Qt如何安排工作(我的意思是,在发送信号之前完成for循环)?在这种情况下,工作的时间表取决于操作系统?这不应该是随机的&#34;?

谢谢大家

1 个答案:

答案 0 :(得分:0)

在控件返回事件循环之前多次调用deleteLater是有效的:

#include <QtCore>
int main(int argc, char ** argv) {
  QCoreApplication app{argc, argv};
  auto obj = new QObject;
  obj->deleteLater();
  obj->deleteLater();
  connect(obj, &QObject::destroyed, []{ qApp->quit(); });
  return app.exec();
}

因此,在我看来,你的问题不是多次调用deleteLater,而是迭代已被破坏的对象集合。 localSocketList不知道正在删除的套接字并包含悬空指针。

有一个简单的补救措施 - 使用一个知道被删除对象的列表。为简单起见,下面的列表是明确共享的,即它的任何副本都引用同一个对象(如果您熟悉它们,那些也是JavaScript语义)。

// https://github.com/KubaO/stackoverflown/tree/master/questions/qobject-pointer-list-43986348
#include <QtCore>

class PointerListData : public QObject, public QSharedData {
   Q_OBJECT
public:
   QVector<QObject*> list;
   void removed() { list.removeAll(sender()); }
   void connect(QObject* obj) {
      QObject::connect(obj, &QObject::destroyed, this, &PointerListData::removed);
   }
   void disconnect(QObject* obj) {
      QObject::disconnect(obj, &QObject::destroyed, this, &PointerListData::removed);
   }
};

template <typename T> class PointerList {
protected:
   QExplicitlySharedDataPointer<PointerListData> d;
public:
   PointerList() : d(new PointerListData) {}
   PointerList(const PointerList &other) : d(other.d) {}
   PointerList(PointerList && other) : d(std::move(other.d)) {}
   void append(T* obj) {
      auto connect = !contains(obj);
      d->list.append(obj);
      if (connect)
         d->connect(obj);
   }
   PointerList & operator<<(T* obj) {
      append(obj);
      return *this;
   }
   int removeAll(T* obj) {
      auto n = d->list.removeAll(obj);
      if (n)
         d->disconnect(obj);
      return n;
   }
   bool contains(T* obj) const {
      return d->list.contains(obj);
   }
   void clear() {
      for (auto obj : d->list)
         d->disconnect(obj);
      d->list.clear();
   }

   void moveToThread(QThread* thread) { d->moveToThread(thread); }
   bool isEmpty() const { return d->list.isEmpty(); }
   int size() const { return d->list.size(); }
   using iterator = T**;
   using const_iterator = const T**;
   iterator begin() { return iterator(d->list.data()); }
   iterator end() { return iterator(d->list.data() + d->list.size()); }
   const_iterator begin() const { return const_iterator(d->list.constData()); }
   const_iterator end() const { return const_iterator(d->list.constData() + d->list.size()); }
   constexpr const PointerList& crange() const noexcept { return *this; }
     // see http://stackoverflow.com/q/15518894/1329652
};

int main(int argc, char ** argv) {
   QCoreApplication app(argc, argv);
   PointerList<QMimeData> list;
   {
      QMimeData a;
      QMimeData b;
      list << &a << &b;
      auto list2 = list;
      Q_ASSERT(list2.size() == 2);
      for (auto obj : list.crange())
         qDebug() << obj;
   }
   Q_ASSERT(list.isEmpty());

}
#include "main.moc"