Why the pointer of QVector always change when use QVector as parameter of signal?
-
wrote on 15 Nov 2021, 02:47 last edited by
Hi,
Recently, I meet a very confuse problem. after a long time troubleshoot, I found the pointer of QVector always change when use QVector as parameter of signal. first I thought I might used the move constructor of QvectorQVector(QVector<T> &&)
, then I write a demo to test this, but actually, I did not call the move constructor but called the copy constuctorQVector(const QVector<T> &)
, and the pointer of the orignal QVector changed! I know when the slot is about to execute, the QVector will copy from the orignal QVector, but the orignal QVector should not be changed right? and there is a const key work to limit the parameter.my test code is:
TestVector.h
#ifndef TESTVECTOR_H #define TESTVECTOR_H #include <QObject> #include <QVector> #include "Vector.h" class TestVector : public QObject { Q_OBJECT public: explicit TestVector(QObject *parent = nullptr); public slots: void handle(const Vector<float>& data); signals: void dataReady(const Vector<float>& data); protected: }; #endif // TESTVECTOR_H
TestVector.cpp
#include "TestVector.h" TestVector::TestVector(QObject *parent) : QObject(parent) { connect(this, &TestVector::dataReady, this, &TestVector::handle, Qt::QueuedConnection); } void TestVector::handle(const Vector<float>& data) { QVector<float> _data; _data.resize(data.size()); for (int i = 0; i < data.size(); i++) { _data[i] = data[i] + 1; } }
Vector.h
#ifndef VECTOR_H #define VECTOR_H #include <QVector> #include <QDebug> template<typename T> class Vector : public QVector<T> { public: Vector() : QVector<T>() { qDebug() << __FUNCTION__ << __LINE__; } Vector(const Vector<T>& other) : QVector<T>(other) { qDebug() << __FUNCTION__ << __LINE__; } Vector(Vector<T> && other) : QVector<T>(other) { qDebug() << __FUNCTION__ << __LINE__; } QVector<T> &operator=(Vector<T> &&other) { qDebug() << __FUNCTION__ << __LINE__; return QVector<T>::operator=(other); } virtual ~Vector() { qDebug() << __FUNCTION__ << __LINE__; } }; Q_DECLARE_METATYPE(Vector<float>) #endif // VECTOR_H
part of test code:
{ qRegisterMetaType<Vector<float>>(); TestVector* test = new TestVector; QThread* thread = new QThread; test->moveToThread(thread); thread->start(); m_data.resize(1024 * 32); for (int i = 0; i < 1000; i++) { qDebug() << "data" << m_data.data(); // Vector<float> _data(data); emit test->dataReady(m_data); } }
-
wrote on 15 Nov 2021, 05:21 last edited by Bonnie
Hey I just test with your code. If you change
m_data.data()
tom_data.constData()
then you'll have the same address.
I think maybe because when you callQVector::data()
it will call something like "detach" and performs a deep copy of the orignal data when there're other copies. -
Hi,
Recently, I meet a very confuse problem. after a long time troubleshoot, I found the pointer of QVector always change when use QVector as parameter of signal. first I thought I might used the move constructor of QvectorQVector(QVector<T> &&)
, then I write a demo to test this, but actually, I did not call the move constructor but called the copy constuctorQVector(const QVector<T> &)
, and the pointer of the orignal QVector changed! I know when the slot is about to execute, the QVector will copy from the orignal QVector, but the orignal QVector should not be changed right? and there is a const key work to limit the parameter.my test code is:
TestVector.h
#ifndef TESTVECTOR_H #define TESTVECTOR_H #include <QObject> #include <QVector> #include "Vector.h" class TestVector : public QObject { Q_OBJECT public: explicit TestVector(QObject *parent = nullptr); public slots: void handle(const Vector<float>& data); signals: void dataReady(const Vector<float>& data); protected: }; #endif // TESTVECTOR_H
TestVector.cpp
#include "TestVector.h" TestVector::TestVector(QObject *parent) : QObject(parent) { connect(this, &TestVector::dataReady, this, &TestVector::handle, Qt::QueuedConnection); } void TestVector::handle(const Vector<float>& data) { QVector<float> _data; _data.resize(data.size()); for (int i = 0; i < data.size(); i++) { _data[i] = data[i] + 1; } }
Vector.h
#ifndef VECTOR_H #define VECTOR_H #include <QVector> #include <QDebug> template<typename T> class Vector : public QVector<T> { public: Vector() : QVector<T>() { qDebug() << __FUNCTION__ << __LINE__; } Vector(const Vector<T>& other) : QVector<T>(other) { qDebug() << __FUNCTION__ << __LINE__; } Vector(Vector<T> && other) : QVector<T>(other) { qDebug() << __FUNCTION__ << __LINE__; } QVector<T> &operator=(Vector<T> &&other) { qDebug() << __FUNCTION__ << __LINE__; return QVector<T>::operator=(other); } virtual ~Vector() { qDebug() << __FUNCTION__ << __LINE__; } }; Q_DECLARE_METATYPE(Vector<float>) #endif // VECTOR_H
part of test code:
{ qRegisterMetaType<Vector<float>>(); TestVector* test = new TestVector; QThread* thread = new QThread; test->moveToThread(thread); thread->start(); m_data.resize(1024 * 32); for (int i = 0; i < 1000; i++) { qDebug() << "data" << m_data.data(); // Vector<float> _data(data); emit test->dataReady(m_data); } }
test result
@Mozzie said in Why the pointer of QVector always change when use QVector as parameter of signal?:
Qt::QueuedConnection
This is why: Qt::QueuedConnection is usually used for signals/slots across threads and in this case all parameters are copied. Do not use queued connection if you do not use threads.
-
@Mozzie said in Why the pointer of QVector always change when use QVector as parameter of signal?:
Qt::QueuedConnection
This is why: Qt::QueuedConnection is usually used for signals/slots across threads and in this case all parameters are copied. Do not use queued connection if you do not use threads.
wrote on 19 Nov 2021, 05:23 last edited by@jsulm
I think this might not because the signal-slot, the pointer of the vector I am using is of the orignal QVector, no matter how much it was copied, the pointer of the orignal one should not be changed.
And I found is I use QVector::data() or QVector::operator[int i], it will call the QVector::detach() function and the pointer is changed, but if I use QVector::constData(), it wouldn't call the QVector::detach() function and the result of QVector::constData() will not change.
Do you know what is the difference between QVector::constData() and QVector::data()? I thought they are just have different return type before, it seems not right now. and why QVector::data() need to call QVector::detach()?Thank you.
-
@jsulm
I think this might not because the signal-slot, the pointer of the vector I am using is of the orignal QVector, no matter how much it was copied, the pointer of the orignal one should not be changed.
And I found is I use QVector::data() or QVector::operator[int i], it will call the QVector::detach() function and the pointer is changed, but if I use QVector::constData(), it wouldn't call the QVector::detach() function and the result of QVector::constData() will not change.
Do you know what is the difference between QVector::constData() and QVector::data()? I thought they are just have different return type before, it seems not right now. and why QVector::data() need to call QVector::detach()?Thank you.
@Mozzie said in Why the pointer of QVector always change when use QVector as parameter of signal?:
I think this might not because the signal-slot, the pointer of the vector I am using is of the orignal QVector
Yes, it is. But only as long as you do not change any of the copies. Qt containers use https://doc.qt.io/qt-5/implicit-sharing.html
As long as you do not change any of the QVector copy they all will point to the same data, so internal pointer will be the same.
But as soon as you change one of the copy it will do detach (as you already mentioned) - the data will be copied for that vector and internal pointer will change.So, what I wrote before is correct.
See https://woboq.com/blog/how-qt-signals-slots-work-part3-queuedconnection.html
Especially "Copying the parameters". -
@jsulm
I think this might not because the signal-slot, the pointer of the vector I am using is of the orignal QVector, no matter how much it was copied, the pointer of the orignal one should not be changed.
And I found is I use QVector::data() or QVector::operator[int i], it will call the QVector::detach() function and the pointer is changed, but if I use QVector::constData(), it wouldn't call the QVector::detach() function and the result of QVector::constData() will not change.
Do you know what is the difference between QVector::constData() and QVector::data()? I thought they are just have different return type before, it seems not right now. and why QVector::data() need to call QVector::detach()?Thank you.
@Mozzie said in Why the pointer of QVector always change when use QVector as parameter of signal?:
and why QVector::data() need to call QVector::detach()?
I think only the non-const data() method will detach. Because you can change internal data using it, so it has to detach.
If you don't want to detach use the const one: https://doc.qt.io/qt-5/qvector.html#data-1 -
@Mozzie said in Why the pointer of QVector always change when use QVector as parameter of signal?:
and why QVector::data() need to call QVector::detach()?
I think only the non-const data() method will detach. Because you can change internal data using it, so it has to detach.
If you don't want to detach use the const one: https://doc.qt.io/qt-5/qvector.html#data-1
1/7