2011-01-26 19 views
7

¿Es posible, y si es así, cómo puedo crear una señal/ranura en Qt que sea una referencia constante a un shared_ptr? Quiero una señal que tiene este aspecto:Qt usando boost :: shared_ptr en una señal/ranura

void signal(shared_ptr<SomeClass> const &)

sé cómo hacer esto sin una referencia constante, que es simplemente el tipo shared_ptr<SomeClass> pero por razones de eficiencia * Me gustaría evitar el copiado. La misma sintaxis para el tipo de referencia no está funcionando:

Q_DECLARE_METATYPE(shared_ptr<SomeClass> const &) 
qRegisterMetaType<shared_ptr<SomeClass> const&>(); 

Muchas de las API estándar tienen QString const & así que supongo que es fundamentalmente posible y que no puedo averiguar la sintaxis.


** El mayor problema para el rendimiento no es el tiempo de copia, pero la cantidad de exclusión mutua de bloqueo/desbloqueo que el objeto se copia a cada receptor - hay un montón de ellos. A medida que los hilos múltiples usan el objeto, esto introduce una notable disminución de velocidad/cuello de botella. Si el shared_ptr hace, de hecho, sólo tiene que utilizar un artículo atómica este costo también es trivial, la pregunta general acerca de referencia constante en las señales permanece sin embargo *

+0

¿No pasar un shared_ptr como una const ref niega el punto de tener un shared_ptr en primer lugar? Simplemente pase un ref/puntero const al objeto en cuestión. – messenger

+1

@messenger, la referencia constante es una optimización para evitar copiar el shared_ptr al llamar a funciones. Es un patrón bastante común. Si siempre pasa por valor (señales o funciones normales), shared_ptr se vuelve bastante costoso en comparación con los punteros normales. Los punteros normales no se pueden usar aquí ya que la vida útil del objeto desde el lado "emitir" no está garantizada. –

+0

@ edA-qa mort-ora-y: ¿el boost shared_ptr usa un mutex? ¿¿¿Por qué eso??? ¿No son todos los incrementos/decrementos atómicos todo lo que necesitas? – mmmmmmmm

Respuesta

7

Hasta ahora he encontrado que simplemente no puedo hacer esto:.

Q_DECLARE_METATYPE(shared_ptr<SomeClass>) 
qRegisterMetaType<shared_ptr<SomeClass> >(); 
qRegisterMetaType<shared_ptr<SomeClass> >("std::shared_ptr<SomeClass>const&"); 

Estoy tratando de verificar ahora si esto realmente funciona correctamente. La documentación aquí no es clara sobre lo que realmente sucede. Parece que el tipo de referencia const en una señal/ranura simplemente se organizará como un shared_ptr<SomeClass> normal, que está totalmente bien aquí. Sin embargo, tener algún tipo de garantía de que esto funcione como tal sería bueno.

Tengo la sensación de que la versión simple shared_ptr<SomeClass> es todo lo que se necesita y es el espacio de nombre boost que está interfiriendo con las señales. La segunda versión aparece solo para registrar la señal en el espacio de nombres global para un uso más fácil.


puedo confirmar, a partir de las pruebas, que la parte const & es, como se alude, completamente ignorado en las conexiones en cola. Cada ranura conectada obtiene una nueva copia del objeto. Esto es muy desafortunado :(

Pruebas adicionales muestran que el & se utiliza para la ranura, pero de una manera inusual. La copia del objeto todavía se crea para la conexión en cola, pero si no utiliza una referencia, otra copia será creado para la llamada.

Por lo tanto, aunque cada connect terminará copiando los datos para una conexión en cola, las referencias aún ayudan un poco. Y también si tiene algunas señales enviadas localmente (mismo hilo) puede evitar incluso más copia

+1

1) Debería poder omitir el argumento de cadena de qRegisterMetaType() alltogether. 2) const ref nunca se necesita para señales/ranuras y el material de metatipos, simplemente el tipo simple. También const ref. y pasar por valor son equivalentes al mecanismo de señal/ranura: Puede conectar una señal de señal vacía (const T &) a través de SIGNAL (señal (const T &)) o SIGNAL (señal (T)), la firma se normaliza a "señal (T) "de todos modos. Cuando se organiza por ej. para una conexión en cola, el valor se almacena mediante copia, no almacenando la referencia. –

+0

@Frank, para las colas Estoy bien con una copia. Me preocupa el envío a los receptores. Si conecto muchas ranuras a una señal con una referencia, ¿se usará una referencia al mismo objeto en todos los casos (es decir, todas las ranuras dentro del mismo hilo)? –

+1

qa, acabo de comprobar las fuentes y parece que Qt crea una copia para cada conexión en cola, es decir, para cada receptor.Si lo desea, marque QMetaObject :: activate() que recorre los remitentes y QMetaObject :: queued_activate() que realiza la copia real, todo en qobject.cpp. –

2

Según una de las respuestas en esta pregunta Argument type for Qt signal and slot, does const reference qualifiers matters?, para una conexión en cola, el objeto se copia independientemente de h Cómo conectas la señal y la ranura.

Dado que está utilizando varios subprocesos, la conexión está en cola. Si teme el costo mutex, intente utilizar SomeClass * directamente.

+0

Copiar a través de los hilos está totalmente bien siempre que solo esté usando el constructor de copia (u operador =). Es dentro de un hilo que no quiero copiar a todos los receptores. –

0

Para completar, creo que debe mencionarse que Qt tiene su propia implementación de puntero compartido, QSharedPointer, que se comporta exactamente como std :: shared_ptr. Eventualmente, aún tendrá que registrar su tipo de argumento.

Cuestiones relacionadas