在Qt的槽函数中修改参数是否安全?

时间:2014-03-19 14:51:10

标签: c++ qt signals-slots

我有一个发出std::vector<uint8_t>的信号,其中包含一堆数据(缓冲区)。

然后在接收对象中,我有一个带有参数std::vector<uint8_t> data

的插槽

然后我尝试解码这些数据。我要做的一件事就是删除填充,例如:

void receive_slot(std::vector<uint8_t> data)
{
    // Remove padding
    if (data.size() > 20)
        data.resize(data.size() - 20);
}

现在,我认为传入的这个论点是一份副本,我可以做我想做的事情&#34;。然而,重做大于10个字节的大小会使我的程序崩溃。我认为重新调整大小不到~10个字节不会因运气而崩溃。

因此,我认为我无法安全地执行此操作,应首先将其复制到新的数据缓冲区。

任何人都可以告诉我这个吗?

2 个答案:

答案 0 :(得分:4)

为问题提供直接的答案:

Qt中的插槽只是正常的函数调用(调用它们的时候和调用它们的差异,由Qt管理),并且修改函数参数(当非const显然时)是完全有效的。当你说你得到一份副本并且你可以“做你想做的事情”时,你是对的。

在这种情况下,错误并非完全来自于您正在修改函数参数的事实。

答案 1 :(得分:2)

您展示的代码完全有效且安全,问题出在代码的其他地方。其他东西正在破坏内存,崩溃发生在receive_slot纯粹的机会。验证这一点非常容易:在将问题提交到SO之前,您应该将下面的最小测试用例放在一起。

适合我。

#include <vector>
#include <QObject>
#include <QCoreApplication>
#include <QAtomicInt>

QAtomicInt n = 0;

class Object : public QObject {
   Q_OBJECT
public:
   Q_SIGNAL void source(const std::vector<uint8_t> &);
   Q_SLOT void sink(std::vector<uint8_t> data) {
      // Remove padding
      if (data.size() > 20)
         data.resize(data.size() - 20);
      n.fetchAndAddOrdered(1);
   }
};
Q_DECLARE_METATYPE(std::vector<uint8_t>)

int main(int argc, char ** argv)
{
   QCoreApplication a(argc, argv);
   qRegisterMetaType<std::vector<uint8_t> >();
   Object src, dstD, dstQ;
   const int N = 1000000;
   // note elision of const & from the parameter types
   dstD.connect(&src, SIGNAL(source(std::vector<uint8_t>)),
               SLOT(sink(std::vector<uint8_t>)));
   dstQ.connect(&src, SIGNAL(source(std::vector<uint8_t>)),
               SLOT(sink(std::vector<uint8_t>)), Qt::QueuedConnection);
   for (int i = 0; i < N; ++i) {
      std::vector<uint8_t> v;
      v.resize(qrand() % 100);
      emit src.source(v);
   }
   a.processEvents();
   Q_ASSERT(n.loadAcquire() == (2*N));
   return 0;
}

#include "main.moc"