2010-06-08 19 views
9

Recientemente he comenzado a investigar Qt para mí mismo y tienen la siguiente pregunta: ¿¿Cómo funciona C++/Qt - La asignación de memoria?

Supongamos que tengo un poco de QTreeWidget* widget. En algún momento quiero añadir algunos elementos a la misma y esto se hace a través de la siguiente llamada:

QList<QTreeWidgetItem*> items; 

// Prepare the items 
QTreeWidgetItem* item1 = new QTreeWidgetItem(...); 
QTreeWidgetItem* item2 = new QTreeWidgetItem(...); 
items.append(item1); 
items.append(item2); 

widget->addTopLevelItems(items); 

Hasta ahora parece bien, pero que en realidad no entiendo quién debe controlar la vida de los objetos. Debo explicar esto con un ejemplo :

Digamos, otra función llama widget->clear();. No sé qué sucede debajo de esta llamada, pero creo que la memoria asignada para item1 y item2 no se elimina aquí, ya que su propietario no se transfirió en realidad. Y, bang, tenemos una pérdida de memoria.

La pregunta es la siguiente - hace Qt tiene algo que ofrecer para este tipo de situación? que podría utilizar boost::shared_ptr o cualquier otro puntero inteligente y escribir algo como

shared_ptr<QTreeWidgetItem> ptr(new QTreeWidgetItem(...)); 
items.append(ptr.get()); 

pero no sé si el propio Qt trataría de hacer explícitas delete llamadas en mi punteros (lo cual sería desastroso desde que los declaro como shared_ptr -managed).

¿Cómo resolvería este problema? Quizás todo sea evidente y extraño algo realmente simple?

Respuesta

7

Un vistazo rápido en qtreewidget.cpp muestra esto:

void QTreeWidget::clear() 
{ 
    Q_D(QTreeWidget); 
    selectionModel()->clear(); 
    d->treeModel()->clear(); 
} 

void QTreeModel::clear() 
{ 
    SkipSorting skipSorting(this); 
    for (int i = 0; i < rootItem->childCount(); ++i) { 
     QTreeWidgetItem *item = rootItem->children.at(i); 
     item->par = 0; 
     item->view = 0; 
     delete item;  // <<----- Aha! 
    } 
    rootItem->children.clear(); 
    sortPendingTimer.stop(); 
    reset(); 
} 

por lo que parece que su llamada a widget-> addTopLevelItems() en verdad causa la QTreeWidget a tomar posesión de los QTreeWidgetItems. Por lo tanto, no debe eliminarlos usted mismo, ni mantenerlos en un shared_ptr, o terminará con un problema de eliminación doble.

4

Qt tiene sus propios indicadores inteligentes, eche un vistazo a http://doc.qt.io/archives/4.6/qsharedpointer.html. Normalmente, es aconsejable utilizar la jerarquía de propiedad estándar de Qt siempre que sea posible. Ese concepto se describe aquí: http://doc.qt.io/archives/4.6/objecttrees.html

Para su ejemplo concreto, esto significa que debe pasar un puntero al contenedor (es decir, el QTreeWidget) al constructor de los objetos secundarios. Cada constructor de subclase QWidget toma un puntero a un QWidget para ese fin. Cuando pasa el puntero de su hijo al contenedor, el contenedor asume la responsabilidad de limpiar a los niños. Así es como se necesita modificar su ejemplo:

QTreeWidgetItem* item1 = new QTreeWidgetItem(..., widget); 
QTreeWidgetItem* item2 = new QTreeWidgetItem(..., widget); 

(no sé qué ... son en su ejemplo, pero lo importante para la gestión de la memoria Qt es el último argumento).

Su ejemplo del uso de un puntero inteligente

shared_ptr<QTreeWidgetItem> ptr(new QTreeWidgetItem(...)); 
items.append(ptr.get()); 

no es una buena idea, porque se rompe la regla de oro de punteros inteligentes: Nunca utilice el puntero en bruto de un objeto puntero inteligente de gestión directa.

+0

M. Entonces, si "enlace" * mis elementos hijo al widget principal mientras escribe, ¿puedo estar seguro de que una llamada 'clear()', por ejemplo, eliminaría esa memoria? –

+0

Sí, puedes. Mientras utilice la gestión de memoria de Qt, Qt se asegura de que todos los objetos se eliminen cuando se elimine su elemento primario (por lo que Qt funciona estrictamente basado en árbol con respecto a la gestión de memoria padre-hijo. – theDmi

+0

Si utiliza el complemento() o addWidget () o funciones similares, no configura explícitamente el padre en el constructor, aunque nunca duele. – rubenvb

1

Muchas instancias de la clase Qt se pueden construir con un QObject padre *. Este padre controla el tiempo de vida del niño construido.A ver si QTreeWidgetItem se pueden vincular a un widget padre, que parece así, la lectura de Qt docs:

Los productos que generalmente se construyen con un padre que es o bien un QTreeWidget (para elementos de nivel superior) o una QTreeWidgetItem (para los artículos en los niveles inferiores del árbol ).