c++ - smart - Qt: ¿Pueden los objetos secundarios estar compuestos en su objeto principal?
solidity ide (7)
La documentación dice que cualquier objeto derivado de QObject se destruirá automáticamente cuando se destruya su padre; esto implica una llamada para eliminar
No. Implica una llamada al destructor de esa entidad particular.
Digamos en su ejemplo, si MyWindow
se destruye, significa que se ha llamado al destructor de MyWindow
. Que a su vez llamará al destructor myButton
que ya está implementado en QPushButton
.
Si tiene una entidad compuesta, solo se llamará al destructor en esa entidad pero no se delete
por lo que no se bloqueará.
Las relaciones padre hijo en Qt no requieren específicamente estar en una pila o montón. Puede ser en cualquier cosa.
Un ejemplo similar en relación padre-hijo sobre una pila está aquí .
HTH ..
En Qt, ¿puedo incrustar widgets secundarios en sus padres a través de la composición, o tengo que crearlos con new
?
class MyWindow : public QMainWindow
{
...
private:
QPushButton myButton;
}
MyWindow::MyWindow ()
: mybutton("Do Something", this)
{
...
}
La documentación dice que cualquier objeto derivado de QObject
se destruirá automáticamente cuando se destruya su padre; esto implica una llamada para delete
, que en el ejemplo anterior se bloquee.
¿Debo usar lo siguiente?
QPushButton* myButton;
myButton = new QPushButton("Do Something", this);
EDITAR
Las respuestas son bastante diversas, y básicamente se reducen a tres posibilidades:
- Sí , la composición está bien. Qt puede averiguar cómo se asignó el objeto y solo
delete
los objetos asignados al montón (¿Cómo funciona esto?) - Sí , la composición está bien, pero no especifique un elemento principal, ya que de lo contrario, el padre llamaría
delete
en el objeto (pero ¿no se convertirá un widget sin padres en una ventana de nivel superior?) - No , los widgets siempre tienen que ser asignados en el montón.
¿Cuál es correcto?
Debes crearlo en el montón, ya que QObject lo destruirá:
class MyWindow : public QMainWindow
{
...
private:
QPushButton *myButton;
}
MyWindow::MyWindow ()
: mybutton( new QPushButton( "Do Something", this) )
{
...
}
El objeto se destruirá solo cuando tenga un puntero principal, para que pueda usar:
MyWindow::MyWindow ()
: mybutton("Do Something", 0)
{
...
}
El operador de delete
llamadas no bloqueará su aplicación, puede leer la siguiente cita
El mecanismo primario-secundario de Qt se implementa en QObject. Cuando creamos un objeto (un widget, un validador o cualquier otro tipo) con un padre, el padre agrega el objeto a la lista de sus elementos secundarios. Cuando se elimina el elemento primario, recorre su lista de elementos secundarios y elimina cada elemento secundario. Los propios niños eliminan a todos sus hijos, y así sucesivamente hasta que no quede ninguno. El mecanismo principal-secundario simplifica enormemente la administración de la memoria, reduciendo el riesgo de pérdidas de memoria. Los únicos objetos a los que debemos llamar delete son los objetos que creamos con new y que no tienen parent. Y si eliminamos un objeto hijo antes que su elemento primario, Qt eliminará automáticamente ese objeto de la lista de elementos secundarios de los elementos principales.
tenga en cuenta que el argumento principal es NULL
por defecto (argumento predeterminado) esto es QPushButton Constructor
QPushButton ( const QString & text, QWidget * parent = 0 )
para que puedas usar
MyWindow::MyWindow () : mybutton( new QPushButton( "Do Something") ){ ... }
y puedes llamar delete
en cualquier componente y en cualquier momento
Qt cuidará este punto
Las variables de miembro no estáticas y no de montón se eliminan cuando se inicia la secuencia de eliminación de ese objeto en particular. Solo cuando se eliminen todos los miembros, irá al destructor de la clase base. Por lo tanto, el miembro de QPushButton myButton se eliminará antes de que se llame a ~ QMainWindow (). Y a partir de la documentación de QObject: "Si eliminamos un objeto hijo antes que su elemento primario, Qt eliminará automáticamente ese objeto de la lista de elementos secundarios del padre". Por lo tanto, no se producirá ningún bloqueo.
Permítanme citar la fuente aquí.
816 QObject::~QObject()
817 {
818 Q_D(QObject);
819 d->wasDeleted = true;
820 d->blockSig = 0; // unblock signals so we always emit destroyed()
821
...
924
925 if (!d->children.isEmpty())
926 d->deleteChildren();
927
928 qt_removeObject(this);
929
930 if (d->parent) // remove it from parent object
931 d->setParent_helper(0);
932
933 #ifdef QT_JAMBI_BUILD
934 if (d->inEventHandler) {
935 qWarning("QObject: Do not delete object, ''%s'', during its event handler!",
936 objectName().isNull() ? "unnamed" : qPrintable(objectName()));
937 }
938 #endif
939 }
...
1897 void QObjectPrivate::deleteChildren()
1898 {
1899 const bool reallyWasDeleted = wasDeleted;
1900 wasDeleted = true;
1901 // delete children objects
1902 // don''t use qDeleteAll as the destructor of the child might
1903 // delete siblings
1904 for (int i = 0; i < children.count(); ++i) {
1905 currentChildBeingDeleted = children.at(i);
1906 children[i] = 0;
1907 delete currentChildBeingDeleted;
1908 }
1909 children.clear();
1910 currentChildBeingDeleted = 0;
1911 wasDeleted = reallyWasDeleted;
1912 }
Como puede ver, QObject
sí delete
cada uno de sus elementos secundarios en el destructor. Además, el destructor se ejecuta antes de los destructores de cualquier miembro; por lo tanto, si el compuesto en cuestión es igual al elemento primario, entonces el miembro QObject
no tendrá ninguna posibilidad de eliminarse de la lista secundaria de su elemento primario.
Esto, desafortunadamente, significa que no puede componer un QObject
en su padre . Pero puedes componer en otros objetos, así como asignar en la pila, tan pronto como garantices que destruyas el objeto o restablecer su padre a 0 antes de que el padre comience a destruir.
Los árboles de objetos y la propiedad responden a su pregunta. Básicamente, cuando el objeto hijo se crea en el montón, será eliminado por su padre.
Por otro lado, cuando se crea el objeto secundario en la pila, el orden de destrucción es importante. El hijo será destruido antes que su padre y se eliminará de la lista de sus padres para que no se invoque su destructor dos veces.
También hay un ejemplo en ese enlace que muestra un orden problemático de destrucción.