Qual è la pratica più sicura nella gestione della durata del puntatore QWidget in un ambiente orientato a QObject?

0

Considera il seguente costruttore:

NetworkTools::NetworkTools(QObject *parent) : QObject(parent)
{
    view = new QWebEngineView();
    view->setParent(parent); // Produces an error, shown below.
}

Mentre QWebEngineView è un QWidget , può essere utilizzato senza dover aprire una finestra di widget, utilizzando:

void QWebEngineView::load(const QUrl &url)

al posto di

void QWidget::show()

Pertanto, lo integrerò in varie applicazioni della console basate su QObject. Il problema, tuttavia, è impostare i genitori. Il codice sopra riportato produce questo errore:

error: invalid conversion from ‘QObject*’ to ‘QWidget*’ [-fpermissive]
view = new QWebEngineView(parent);
                                ^

Secondo questa risposta su SO ,

Qt is not designed to support a non-widget parent to a QWidget

ma poi afferma più tardi:

It's not a worthwhile fight, I think - not unless a decision is made to make a QWidget truly-a QObject and change its constructor signature. That can be done at the earliest in Qt 6 since it's a binary-incompatible change AFAIK.

Si suggerisce che il casting del genitore porti solo a problemi, quindi la mia soluzione è solo assicurarsi che tutti i miei puntatori QWidget appartengano a una classe e semplicemente eliminarli nel distruttore della classe in questo modo:

NetworkTools::~NetworkTools() {delete view;}

Compromettere la funzionalità setParent. Non sono nemmeno sicuro se questo è il modo corretto per eliminare un puntatore QWidget . In quanto tale:

  1. È vero che Qt6 pianifica di lasciare che QObject funga da genitore QWidget ?

  2. Il mio metodo di distruttore è corretto, ed è una strategia sicura per prevenire perdite di memoria?

  3. È disponibile una pratica più sicura?

  4. Dovrei utilizzare uno dei puntatori intelligenti di Qts:

Grazie.

    
posta Akiva 10.04.2018 - 22:31
fonte

2 risposte

2

1.

La tua risposta SO collegata parla solo del primo punto possibile in cui potrebbe verificarsi un tale cambiamento. Personalmente non ho mai visto una proposta o una discussione sul fatto di fare qualcosa del genere.

2. a 4.

tl; dr: allontana il problema e rendi la vista un membro normale di NetworkTools .

Risposta più lunga: il tuo approccio utilizza RAII, che è il modo preferito per gestire la proprietà in C ++. Questo è perfettamente valido, ma in questo caso non è l'ideale.

Dalla tua domanda non riesco a vedere un motivo per cui dovresti allocare il QWebEngineView al di fuori di NetworkTools . Può essere un membro normale di NetworkTools . È legato alla durata di NetworkTools in ogni caso e si eviterà qualsiasi lavoro speciale nel ctor o nel dtor e una serie di riferimenti indiretti al puntatore quando si accede al membro view .

Potresti voler allocare la vista separatamente se è enorme e vuoi allocare (molti)% oggetti% co_de nello stack, anche se ciò sembra improbabile. Con oggetti enormi, l'esaurimento dello stack è una possibilità reale. Tuttavia, sul mio Qt 5.10 a 64 bit Linux NetworkTools . Non è molto piccolo, ma niente di cui preoccuparsi. Per confronto: sizeof(QWebEngineView) == 56 e sizeof(QString) == 8 .

Se devi assolutamente allocare la vista separatamente, preferisci sizeof(QObject) == 16 per il semplice motivo che è il puntatore intelligente di proprietà singola predefinito fornito dalla libreria standard C ++ stessa. I puntatori intelligenti di Qt provengono per lo più in tempi antichi quando il C ++ non aveva puntatori intelligenti. Ci sono due situazioni in cui prenderei in considerazione un puntatore intelligente Qt:

  • Se volessi sfruttare il sistema di condivisione implicita / copy-on-write di Qt. Ecco a cosa servono i puntatori SharedData .
  • Per evitare inutili conversioni se dovessi utilizzare una parte dell'API di Qt che richiede un puntatore intelligente Qt.

Per tutto il resto, ho impostato come predefinito std::unique_ptr o std::unique_ptr per i pochi casi speciali in cui hai una reale proprietà condivisa.

    
risposta data 11.04.2018 - 18:36
fonte
2
  1. Ne dubito. Penso che quello che volevano dire è che se quel cambiamento sarà fatto a QWidget, non sarà fatto prima di Qt6, perché sta rompendo la compatibilità binaria, ma non è scontato che sarà fatto.

  2. Non conosco il tuo codice, ma in generale Qt distrugge automaticamente tutti i child, cioè i widget con un genitore, quando il genitore viene distrutto. Quindi devi solo distruggere i widget senza un genitore.

  3. e 4. Imho sì, l'uso di puntatori intelligenti è più sicuro, perché diventa molto più difficile gestire male la distruzione (dimenticando la distruzione o distruggendo più volte). Come linea guida generale, se non si condividono i puntatori tra più utenti, utilizzare QScopedPointer, altrimenti utilizzare QSharedPointer. Gli altri sono versioni più specializzate. Puoi anche utilizzare boost o C ++ 11 scopeed_ptr e shared_ptr.

risposta data 11.04.2018 - 11:45
fonte

Leggi altre domande sui tag