首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QDataStream QIODevice内存分配

QDataStream QIODevice内存分配
EN

Stack Overflow用户
提问于 2012-10-24 05:32:05
回答 2查看 1.3K关注 0票数 2

假设我有一个创建QIODevice (例如QFile)的函数,然后返回一个指向从QIODevice构造的QDataStream的指针。在这里处理内存分配的最好方法是什么?显然,必须对QIODevice进行堆分配,以便在函数终止时保持对QDataStream的可用性,但是销毁QDataStream并不会销毁或关闭设备。有没有一种标准的方法来处理这个看似常见的问题?理想情况下,我想要一个函数返回一个对象(而不是指向对象的指针),该对象的行为类似于QDataStream,但在销毁时会关闭设备。一个有效的标准库输入流。

示例代码:

代码语言:javascript
复制
QDataStream* getStream(const QString& filename) {
  QFile* file = new QFile(filename); // needs to be explicitly deleted later
  file->open(QIODevice::ReadOnly);
  QDataStream* out = new QDataStream(&file); // same here
  return out;
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-10-24 06:27:36

代码语言:javascript
复制
std::shared_ptr<QDataStream> getStream(const QString& filename) 
{
  QFile* file = new QFile(filename); // needs to be explicitly deleted later
  file->open(QIODevice::ReadOnly);
  std:shared_ptr<QDataStream> out(new QDataStream(&file), QDSDeleter);
  return out;
}

void QDSDeleter(QDataStream* s)
{
   QIODevice* device = s->device();
   device->close();
   delete device;
}

根据您的需要,std::unique_ptr是另一种选择;如果您需要的话,可以使用here's a reference

Edit: Qt还通过其QSharedPointer类提供了此功能,您还可以提供一个删除器作为构造函数参数。这里还给出了其他指针包装选项。谢谢@RA。以进行修正。

票数 5
EN

Stack Overflow用户

发布于 2018-07-27 06:28:17

QDataStream有一个方便的owndev私有成员,您可以将其设置为true,以使流有效地拥有设备。流也可以很容易地移动-使它非常接近您的需求,它的行为像一个值。理想情况下,您可以修改您的Qt副本来实现它,但也可以解决这个问题。

代码语言:javascript
复制
// https://github.com/KubaO/stackoverflown/tree/master/questions/qdatastream-move-own-13039614
#include <QDataStream>

class DataStream : public QDataStream {
   struct Proxy {
      QScopedPointer<QDataStreamPrivate> d;
      QIODevice *dev;
      bool owndev;
      bool noswap;
      QDataStream::ByteOrder byteorder;
      int ver;
      QDataStream::Status q_status;
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
      virtual ~Proxy();
#endif
   };
   static Proxy *p(QDataStream *ds) { return reinterpret_cast<Proxy *>(ds); }
   static const Proxy *p(const QDataStream *ds) {
      return reinterpret_cast<const Proxy *>(ds);
   }
#if defined(QT_TESTLIB_LIB) || defined(QT_MODULE_TEST)
   friend class DataStreamTest;
#endif
  public:
   DataStream() = default;
   using QDataStream::QDataStream;
   DataStream(DataStream &&other) : DataStream(static_cast<QDataStream &&>(other)) {}
   DataStream(QDataStream &&other) {
      using std::swap;
      Proxy &o = *p(&other);
      Proxy &t = *p(this);
      swap(t.d, o.d);
      swap(t.dev, o.dev);
      swap(t.owndev, o.owndev);
      swap(t.noswap, o.noswap);
      swap(t.byteorder, o.byteorder);
      swap(t.ver, o.ver);
      swap(t.q_status, o.q_status);
   }
   DataStream &operator=(DataStream &&other) {
      return *this = static_cast<QDataStream &&>(other);
   }
   DataStream &operator=(QDataStream &&other) {
      this->~DataStream();
      new (this) DataStream(std::move(other));
      return *this;
   }
   void setOwnedDevice(QIODevice *dev) {
      setDevice(dev);
      p(this)->owndev = true;
   }
   bool ownsDevice() const { return p(this)->owndev; }
   static bool ownsDevice(const QDataStream *ds) { return p(ds)->owndev; }
};

由于QObject有一个内置的引用计数,如果我们愿意的话,我们也可以让QDataStream作为它的共享指针。

以下要求在Qt 4.8和5.10上进行了测试:

代码语言:javascript
复制
PASS   : DataStreamTest::isBinaryCompatible()
PASS   : DataStreamTest::streams()
PASS   : DataStreamTest::movesFromNotOwnedQDataStream()
PASS   : DataStreamTest::movesFromNotOwnedDataStream()
PASS   : DataStreamTest::assignsFromNotOwnedQDataStream()
PASS   : DataStreamTest::assignsFromNotOwnedDataStream()
PASS   : DataStreamTest::returnsFromNotOwnedQDataStream()
PASS   : DataStreamTest::returnsFromNotOwnedDataStream()
PASS   : DataStreamTest::movesFromOwnedQDataStream()
PASS   : DataStreamTest::moveFromOwnedDataStream()
PASS   : DataStreamTest::assignsFromOwnedQDataStream()
PASS   : DataStreamTest::assignsFromOwnedDataStream()
PASS   : DataStreamTest::returnsFromOwnedQDataStream()
PASS   : DataStreamTest::returnsFromOwnedDataStream()

下面是测试套件。二进制兼容性测试是广泛的,几乎排除了我们所依赖的UB存在问题的可能性。请注意,QDataStream的布局不能在主要的Qt版本中更改-因此上面的代码将在所有未来的Qt 5版本中工作。

代码语言:javascript
复制
#include <QtTest>

class DataStreamTest : public QObject {
   Q_OBJECT
   static QObjectData *getD(QObject *obj) {
      return static_cast<DataStreamTest *>(obj)->d_ptr.data();
   }
   static bool wasDeleted(QObject *obj) { return getD(obj)->wasDeleted; }
   template <typename T, typename... Args>
   DataStream make_stream(Args &&... args) {
      return T(std::forward<Args>(args)...);
   }
   static QDataStream::ByteOrder flipped(QDataStream::ByteOrder o) {
      return (o == QDataStream::BigEndian) ? QDataStream::LittleEndian
                                           : QDataStream::BigEndian;
   }
   Q_SLOT void isBinaryCompatible() {
      QCOMPARE(sizeof(DataStream), sizeof(QDataStream));
      QCOMPARE(sizeof(DataStream::Proxy), sizeof(QDataStream));
      struct Test {
         QByteArray data;
         QDataStream ds{&data, QIODevice::ReadWrite};
         void check(int loc = 0) {
            if (!loc) {
               check(1);
               ds.setDevice(nullptr);
               check(1);
            }
            QCOMPARE(!!ds.device(), DataStream::ownsDevice(&ds));
            QCOMPARE(ds.device(), DataStream::p(&ds)->dev);

            if (!loc) check(2);
            bool noswap = DataStream::p(&ds)->noswap;
            QCOMPARE(noswap, DataStream::p(&ds)->noswap);
            QCOMPARE(ds.byteOrder(), DataStream::p(&ds)->byteorder);
            if (loc != 2) {
               ds.setByteOrder(flipped(ds.byteOrder()));
               noswap = !noswap;
            }
            if (!loc) check(2);
            QCOMPARE(noswap, DataStream::p(&ds)->noswap);

            if (!loc) check(3);
            QCOMPARE(ds.version(), DataStream::p(&ds)->ver);
            if (loc != 3) ds.setVersion(QDataStream::Qt_4_0);
            if (!loc) check(3);

            if (!loc) check(4);
            QCOMPARE(ds.status(), DataStream::p(&ds)->q_status);
            if (loc != 4) ds.setStatus(QDataStream::ReadPastEnd);
            if (!loc) check(4);
         }
      } test;
      test.check();
   }
   Q_SLOT void streams() {
      QString str{"Hello, world"};
      QVector<uint> ints{44, 0xDEADBEEF, 1};
      QByteArray data;
      DataStream ds(&data, QIODevice::ReadWrite);
      ds << str << ints;
      ds.device()->reset();
      QString str2;
      QVector<uint> ints2;
      ds >> str2 >> ints2;
      QCOMPARE(str2, str);
      QCOMPARE(ints2, ints);
   }
   Q_SLOT void movesFromNotOwnedQDataStream() {
      QBuffer buf;
      QDataStream ds(&buf);
      QVERIFY(ds.device() == &buf);
      DataStream ds2(std::move(ds));
      QVERIFY(!ds.device());
      QVERIFY(ds2.device() == &buf);
      QVERIFY(!wasDeleted(&buf));
   }
   Q_SLOT void movesFromNotOwnedDataStream() {
      QBuffer buf;
      DataStream ds(&buf);
      QVERIFY(ds.device() == &buf);
      DataStream ds2(std::move(ds));
      QVERIFY(!ds.device());
      QVERIFY(ds2.device() == &buf);
      QVERIFY(!wasDeleted(&buf));
   }
   Q_SLOT void assignsFromNotOwnedQDataStream() {
      QBuffer buf;
      QDataStream ds(&buf);
      QVERIFY(ds.device() == &buf);
      DataStream ds2;
      ds2 = std::move(ds);
      QVERIFY(!ds.device());
      QVERIFY(ds2.device() == &buf);
      QVERIFY(!wasDeleted(&buf));
   }
   Q_SLOT void assignsFromNotOwnedDataStream() {
      QBuffer buf;
      DataStream ds(&buf);
      QVERIFY(ds.device() == &buf);
      DataStream ds2;
      ds2 = std::move(ds);
      QVERIFY(!ds.device());
      QVERIFY(ds2.device() == &buf);
      QVERIFY(!wasDeleted(&buf));
   }
   Q_SLOT void returnsFromNotOwnedQDataStream() {
      QBuffer buf;
      {
         auto ds = make_stream<QDataStream>(&buf);
         QVERIFY(ds.device());
         QVERIFY(!ds.ownsDevice());
      }
      QVERIFY(!wasDeleted(&buf));
   }
   Q_SLOT void returnsFromNotOwnedDataStream() {
      QBuffer buf;
      buf.open(QIODevice::ReadWrite);
      {
         auto ds = make_stream<DataStream>(&buf);
         QVERIFY(ds.device());
         QVERIFY(!ds.ownsDevice());
      }
      QVERIFY(!wasDeleted(&buf));
   }
   Q_SLOT void movesFromOwnedQDataStream() {
      QPointer<QIODevice> buf;
      {
         QByteArray data;
         QDataStream ds(&data, QIODevice::ReadWrite);
         QVERIFY(DataStream::ownsDevice(&ds));
         buf = ds.device();
         DataStream ds2(std::move(ds));
         QVERIFY(!ds.device());
         QVERIFY(ds2.device() == buf);
         QVERIFY(buf);
      }
      QVERIFY(!buf);
   }
   Q_SLOT void moveFromOwnedDataStream() {
      QPointer<QBuffer> buf(new QBuffer);
      {
         DataStream ds;
         ds.setOwnedDevice(buf);
         QVERIFY(ds.device() == buf);
         DataStream ds2(std::move(ds));
         QVERIFY(!ds.device());
         QVERIFY(ds2.device() == buf);
         QVERIFY(buf);
      }
      QVERIFY(!buf);
   }
   Q_SLOT void assignsFromOwnedQDataStream() {
      QPointer<QIODevice> buf;
      {
         QByteArray data;
         QDataStream ds(&data, QIODevice::ReadWrite);
         QVERIFY(DataStream::ownsDevice(&ds));
         buf = ds.device();
         DataStream ds2;
         ds2 = std::move(ds);
         QVERIFY(!ds.device());
         QVERIFY(ds2.device() == buf);
         QVERIFY(buf);
      }
      QVERIFY(!buf);
   }
   Q_SLOT void assignsFromOwnedDataStream() {
      QPointer<QBuffer> buf(new QBuffer);
      {
         DataStream ds;
         ds.setOwnedDevice(buf);
         QVERIFY(ds.device() == buf);
         DataStream ds2;
         ds2 = std::move(ds);
         QVERIFY(!ds.device());
         QVERIFY(ds2.device() == buf);
         QVERIFY(buf);
      }
      QVERIFY(!buf);
   }
   Q_SLOT void returnsFromOwnedQDataStream() {
      QPointer<QIODevice> dev;
      QByteArray data;
      {
         auto ds = make_stream<QDataStream>(&data, QIODevice::ReadWrite);
         dev = ds.device();
         QVERIFY(ds.device());
         QVERIFY(ds.ownsDevice());
      }
      QVERIFY(!dev);
   }
   Q_SLOT void returnsFromOwnedDataStream() {
      QPointer<QIODevice> dev;
      QByteArray data;
      {
         auto ds = make_stream<DataStream>(&data, QIODevice::ReadWrite);
         dev = ds.device();
         QVERIFY(ds.device());
         QVERIFY(ds.ownsDevice());
      }
      QVERIFY(!dev);
   }
};

QTEST_MAIN(DataStreamTest)
#include "main.moc"
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13039614

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档