PDA

View Full Version : Safety of emitting a signal with a reference



Momergil
3rd July 2014, 18:13
Hello!

Suppose I want to emit a signal that sends not some data, but the reference of that data (less memory consumption). Would that be safe if the variable referenced to is local to the method and the connection is not a Qt::DirectConnection? Or even in this situation that wouldn't be safe, so one should always use non-reference parameter in his signals?

Thanks,

Momergil

stampede
3rd July 2014, 19:03
No, its asking for trouble. It is like a function returing a pointer to local data - after singal is emitted, local data will be destroyed during the stack unwinding. If you pass a reference (/ pointer) to that data outside of this function, via deferred signal or by return statement, you are giving someone a handle to non-existing object. And I'm pretty sure you know how bad this is :)


void Class::badIdea(){
BigData data = ...;
emit dataOut(&data); // if connection is queued you are in trouble
} // data is DEADBEEF now :) and queued signal is maybe still waiting in the queue...

If you are afraid of the cost of copy operation, use resource handles like containers (which are implicitly shared) or use shared pointers explicitly.
You can also just use heap-allocated object and emit it directly, but I'd rather avoid the headaches related to ownership rules:


void Class::func(){
// we dont want to copy the BigData, so we are "smart" - we use heap allocation and simply send a pointer
BigData * data = new BigData();
emit dataOut(data);
// questions :
// 1. who should delete the data ?
// 2. what if no one is connected ?
}

and with shared pointers:


typedef QSharedPointer<BigData> BigDataPtr;

void Class::func(){
BigDataPtr data(new BigData);
emit dataOut(data);
// answers for free:
// 1. shared data will be deleted when underlying shared ptr's reference counter drops to zero
// 2. no problem, data is deleted automatically as the only shared pointer referencing the data will be gone soon
}

Momergil
4th July 2014, 14:56
Thanks stampede for your reply! :)

One last question that still isn't clear enough: you sad in your first "badIdea()" code:



if connection is queued


so actually such problems only exists in non-direct connections, right? Which means that if the situation allows me, another way of going around this problem is making my connection a Qt::DirectionConnection, right?

stampede
4th July 2014, 15:17
From Qt docs:


Qt::DirectConnection: The slot is invoked immediately when the signal is emitted. The slot is executed in the signalling thread.

So basically it is like a normal function call. But if you want to force DirectConnection type, then why bother with signals / slots ? :)

anda_skoa
4th July 2014, 15:17
Yes, but most often the connection is made by code that is external to both sender and receiver, so neither can really rely on the direct connection.

This requires explicit documentation and that developers read said documentation :)

Cheers,
_

Momergil
4th July 2014, 18:00
then why bother with signals / slots ? :)

For improved code organization, of course :) (no reason to go including header files from classes not directly related to the one in which I'm emitting the signal just to call one of his methods!)


Yes, but most often the connection is made by code that is external to both sender and receiver, so neither can really rely on the direct connection.

Ok, so my turn-around solution flew away =( I guess I'll move to shared pointers after all (or including the header file and calling the method I want to use :p)

Thanks for your reply!

Momergil