【问题标题】:Does dereferencing a pointer create a copy in this example?在此示例中,取消引用指针是否会创建副本?
【发布时间】:2013-02-19 08:13:32
【问题描述】:

我正在尝试优化一些代码,因为我必须将相同的 QPixmap 多次绘制到更大的 QPixmap 上。由于在我自己的方法中按值传递 QPixmap 会在每次调用时创建副本,我想我可以通过使用指向 QPixmaps 的指针来节省一些时间。然而,我的工作似乎一直在进行。我认为这是因为调用 QPainter::drawPixmap(..., const QPixmap&, ...) 会创建它的副本。

QPixmap *pixmap = new QPixmap(10,10);
painter.drawPixmap(0,0, *pixmap);

此示例中是否正在创建副本?

如果是这样,我该如何优化将许多图像绘制到另一个上?

我已经在此处阅读了此问答:Does dereferencing a pointer make a copy of it?,但我无法为我的具体案例找到明确的答案。

【问题讨论】:

    标签: c++ qt dereference qpixmap


    【解决方案1】:

    没有。函数drawPixmap 采用constpixmap 的引用,因此不会进行复制。下面是 QPainter 成员函数的原型:

      void  drawPixmap ( int x, int y, const QPixmap & pixmap )
    

    【讨论】:

      【解决方案2】:

      根据QPixmap class reference

      QPixmap 对象可以通过值传递,因为 QPixmap 类 使用隐式数据共享。有关详细信息,请参阅隐式 数据共享文档。

      QPixmap 实现:

      QPixmap::QPixmap(const QPixmap &pixmap)
          : QPaintDevice()
      {
          if (!qt_pixmap_thread_test()) {
              init(0, 0, QPixmapData::PixmapType);
              return;
          }
          if (pixmap.paintingActive()) {                // make a deep copy
              operator=(pixmap.copy());
          } else {
              data = pixmap.data;
          }
      }
      

      只有当像素图处于活动状态时,您才需要深拷贝,否则新的像素图只需要复制原始数据指针。

      关于const引用和指针的区别:

      QPixmap largeMap(1000, 1000);
      QPainter p(&largeMap);
      
      int count = 100000;
      qint64 time1, time2;
      QPixmap *pSmallMap = new QPixmap("e:/test.png");
      QPixmap smallMap = QPixmap("e:/test.png");
      
      time1 =  QDateTime::currentMSecsSinceEpoch();
      for (int i = 0; i < count; ++i) {
          p.drawPixmap(0, 0, *pSmallMap);
      }
      time2 =  QDateTime::currentMSecsSinceEpoch();;
      qDebug("def time = %d\n", time2 - time1);
      
      time1 =  QDateTime::currentMSecsSinceEpoch();
      for (int i = 0; i < count; ++i) {
          p.drawPixmap(0, 0, smallMap);
      }
      time2 =  QDateTime::currentMSecsSinceEpoch();;
      qDebug("normal time = %d\n", time2 - time1);
      

      在 Visual Studio 2010 Debug 配置下编译会产生以下程序集:

          28:         p.drawPixmap(0, 0, *pSmallMap);
      003B1647 8B 55 C4             mov         edx,dword ptr [ebp-3Ch]  //the pixmap pointer
      003B164A 52                   push        edx  
      003B164B 6A 00                push        0  //x
      003B164D 6A 00                push        0  //y
      003B164F 8D 4D F0             lea         ecx,[ebp-10h]  //the qpainter pointer
      003B1652 FF 15 9C D7 3B 00    call        dword ptr [__imp_QPainter::drawPixmap (3BD79Ch)]
      
          35:         p.drawPixmap(0, 0, smallMap);
      003B16A8 8D 4D E0             lea         ecx,[ebp-20h]  //the pixmap pointer
      003B16AB 51                   push        ecx            
      003B16AC 6A 00                push        0              //x
      003B16AE 6A 00                push        0              //y
      003B16B0 8D 4D F0             lea         ecx,[ebp-10h]  //the qpainter pointer
      003B16B3 FF 15 9C D7 3B 00    call        dword ptr [__imp_QPainter::drawPixmap (3BD79Ch)]  
      

      这两者应该没有区别,因为编译器会产生相同的汇编代码:将指针传递给drawPixmap函数。

      并且 QDateTime::currentMSecsSinceEpoch() 在我的盒子上几乎显示相同的结果。

      【讨论】:

      • 可能严格不正确。在他的情况下,他实际上是通过引用传递的,所以没关系。如果他按值传递,它肯定会有一些,虽然可能可以忽略不计,但比引用传递机制更大。
      • 对..每100k次抽奖的差异只有1秒左右。
      • @Sosukodo:由于您的代码使用引用,因此引用和点之间应该没有性能差异。您如何获得性能差异?
      • 我是怎么计算出来的?基本上是 QDateTime::currentMSecsSinceEpoch() 在 100k 调用 drawPixmap 之前和之后的增量。
      • 谢谢。你肯定赚到了!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多