c++ qt signals-slots qt-signals

c++ - qt connect



Eliminación de objetos enviados por señales, propiedad de objetos en señales, Qt (4)

En 1): El remitente debe tener cuidado. Cuando se envía la señal de forma síncrona (en lugar de en cola), el objeto sigue vivo cuando un receptor lo recibe. Si el receptor necesita almacenarlo, solo un QPointer ayudaría, pero luego MyClass necesita derivar de QObject, que se ve mal en el contexto. De todos modos, ese es un problema general de por vida, no muy específico de señal / ranura.

Alternativas: use una clase de valor y envíela por referencia constante. Si MyClass puede tener subclases, pase una constante QSharedPointer &

Acerca de deleteLater: deleteLater () no ayuda aquí. Haría las conexiones en cola más seguras, y para las conexiones directas no hace ninguna diferencia. El único uso en el que deleteLater () entra en juego es si el receptor necesita eliminar el remitente. Entonces, siempre se debe usar deleteLater (), para que el remitente pueda completar lo que estaba haciendo, lo que de otro modo se bloquearía.

Aquí, mi declaración de señal:

signals: void mySignal(MyClass *);

Y como lo estoy usando:

MyClass *myObject=new myClass(); emit mySignal(myObject);

Aquí viene mi problema: ¿Quién es responsable de la eliminación de myObject:

  1. Código del remitente, ¿qué sucede si se elimina antes de que se use myObject? Puntero que cuelga

  2. La ranura conectada a la señal, ¿qué sucede si no hay una ranura o más de una ranura que esté conectada a la señal? Pérdida de memoria o puntero que cuelga

¿Cómo maneja Qt esta situación en sus señales integradas? ¿Utiliza el recuento de referencias internas?

¿Cuáles son sus mejores prácticas?


En una palabra (bien, nombre de función) - deleteLater () :) Todos los QObjects lo tienen. Marcará el objeto para su eliminación, y esto ocurrirá en la próxima actualización del bucle de eventos.


Para su primera pregunta, use QPointer

Para tu segunda pregunta,

Si entendí claramente, incluso si está enviando myObject , todavía tiene la referencia myObject en la clase en la que está emitiendo la señal. Entonces, ¿cómo será una pérdida de memoria o un puntero que cuelga? Todavía puedes acceder al myObject desde la clase emitida, ¿no?

Espero que quede claro ..

Editar:

Por sus comentarios, creo que está liberando / eliminando los objetos en las ranuras. Ahora asumo que su problema es, ¿qué pasa si la ranura (de liberación de memoria) se llama una vez, dos veces o no se llama en absoluto.

Puedes usar QPointer para eso. De la documentación de Qt,

Los punteros QPointer ( QPointer ) son útiles siempre que necesite almacenar un puntero a un objeto QObject que es propiedad de otra persona y, por lo tanto, podría ser destruido mientras aún mantiene una referencia a él. Puede probar con seguridad el puntero para la validez.

Un ejemplo de la propia documentación de Qt,

QPointer<QLabel> label = new QLabel; label->setText("&Status:"); ... if (label) label->show();

La explicación continúa así.

Si se elimina la QLabel mientras tanto, la variable de etiqueta mantendrá 0 en lugar de una dirección no válida, y la última línea nunca se ejecutará. Aquí QLabel será tu MyClass y la etiqueta será tu myObject . Y antes de usarlo verifica la nulidad .


Puede conectar una señal con tantas ranuras como desee, por lo que debe asegurarse de que ninguna de esas ranuras pueda hacer algo que no quisiera que hicieran con su objeto:

  • Si decide pasar un puntero como parámetro, entonces estará ejecutando los problemas que describe, gestión de memoria: aquí nadie puede hacer el trabajo por usted, ya que tendrá que establecer una política para tratar con la asignación / eliminación. Para algunas ideas sobre cómo abordar esto, consulte las Reglas de administración de memoria en el mundo COM .
  • Si decide pasar un parámetro como referencia, no tiene que preocuparse por la administración de la memoria, sino solo por las ranuras que modifican su objeto de manera inesperada. La idea es no pasar punteros a menos que tenga que hacerlo, en su lugar use referencias si puede.
  • Si decide pasar una referencia const , entonces, dependiendo de su tipo de conexión, QT pasará el valor del objeto por usted (vea this para algunos detalles)
  • Evita cualquier problema y pasa por valor :)

Vea también esta question para algunos pensamientos acerca de pasar punteros en señales.