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

Is it safe to modify an argument from in a slot function in Qt?

本文关键字:参数 是否 安全 函数 Qt 修改      更新时间:2023-10-16

我有一个信号,发出一个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);
}

现在,我认为传入的参数是一个副本,我可以"做我想做的"。但是,如果重新设置大于10字节的大小,我的程序就会崩溃。我假设调整小于~10字节的大小不会使它崩溃,这只是运气。

因此,我认为我不能安全地这样做,应该首先将它复制到一个新的数据缓冲区。

关于这一点,谁能给我点化一下吗?

提供对问题的直接回答:

槽在Qt只是正常的函数调用(何时和与它们被调用的参数是不同的,由Qt管理),它是完全有效的修改函数参数(当非const明显)。你说给你一份拷贝,你可以"用它做你想做的事",这是对的。

在这种情况下,错误并不纯粹是因为您修改了函数参数。

您显示的代码是完全有效和安全的,问题在代码的其他地方。其他东西正在破坏内存,而崩溃纯粹是偶然发生在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"