2013-05-21 11 views
13

Voglio usare C++ 11 Smart Pointers in nuovi progetti e riscontrare un problema. Molti progetti correnti utilizzano ancora puntatori grezzi come parametri nella loro interfaccia e non hanno un'interfaccia per i puntatori intelligenti, ad es. QMainWindow::setCentralWidget.Esiste un modo sicuro per utilizzare C++ 11 Smart Pointer e l'interfaccia per Raw Pointer insieme?

Per mantenere tipo coerente, devo passare il puntatore memorizzato get() come questo segmento:

QMainWindow win; 

std::shared_ptr<QWidget> scrollArea{ std::make_shared<QScrollArea>() }; 
// QScrollArea is a derived class of QWidget. 

win.setCentralWidget(scrollArea.get()); 

Ma non posso fare in modo che altri metodi in Qt vengono eseguiti operatore delete sul puntatore memorizzato di scrollArea .

Causa perdita di memoria o altri problemi se alcuni metodi in Qt lo fanno?

Ho controllato l'ultimo C++ Standard CD e non ho trovato nulla. Sembra che sia un comportamento indefinito.

Se ciò comporta un comportamento indefinito e pericoloso, esiste un modo sicuro per utilizzare puntatori intelligenti con l'interfaccia per i puntatori raw?

+2

Se non si è certi che Qt esegua "cancella", come si assicura che non vi siano perdite di memoria al momento? – hmjd

+2

È lo stesso come se si chiedesse "l'eliminazione di un puntatore due volte causa alcuni problemi?" –

+0

@ W.B. Il mio scopo principale è trovare una soluzione per questo caso. – UniversE

risposta

16

Non c'è modo di procedere nel caso generale. Per ogni interfaccia "legacy" che si desidera utilizzare, è necessario leggere la relativa documentazione per vedere come interagisce con la proprietà (che è ciò che incapsula gli smart pointers std). Un singolo oggetto può essere gestito solo da uno schema di proprietà.

Con Qt in particolare, è sicuramente non sicuro mixare puntatori intelligenti e gestione Qt. La relazione genitore/figlio di Qt tra QObject s include la semantica della proprietà (i figli vengono eliminati quando il loro genitore è), quindi non è possibile combinarlo in modo sicuro con nessun altro schema di proprietà (come i puntatori intelligenti std).

Si noti che il Qt DOC si collega a dichiarare esplicitamente che "QMainWindow assume la proprietà del widget puntatore e lo elimina al momento opportuno."

3

Sfortunatamente, se si utilizza un'interfaccia che utilizza puntatori grezzi, è necessario consultare la documentazione per determinare se il metodo non assume la proprietà del puntatore fornito.

Se la funzione diventa di proprietà, è necessario richiamare .release() per trasferire la proprietà alla funzione. Se la funzione non assume la proprietà, passare l'oggetto con .get().

3

Intende causare perdita di memoria o altri problemi se alcuni metodi in Qt lo fanno?

Non introduce una perdita di memoria, poiché la memoria viene comunque rilasciata. Tuttavia, dal momento che sia QT che chiamerebbero delete su quella memoria, probabilmente si otterrebbe un bel danneggiamento dell'heap (UB in generale).

c'è un modo sicuro per utilizzare puntatori intelligenti con l'interfaccia per i puntatori raw?

Sicuro. Non avere entità indipendenti che gestiscono la stessa memoria.Per questo è consigliabile utilizzare unique_ptr anziché shared_ptr quando possibile. Con unique_ptr è possibile chiamare .release() per rilasciare la memoria dal controllo dello smartpointer, offrendo così la possibilità di dare il controllo a QT.

Ovviamente è necessario controllare la documentazione per vedere quando è necessario gestire la memoria da soli e quando QT lo farà per voi.

3

Se si utilizza un'interfaccia che utilizza puntatori grezzi, si ha già il problema di conoscere chi è responsabile della durata di tali puntatori.

L'aggiunta di shared_ptr nel mix non lo modifica.

Se l'interfaccia può eliminare l'oggetto, non è possibile utilizzare std::shared_ptr in modo sicuro. std::shared_ptr deve controllare la durata dei suoi oggetti e non c'è modo di aggirare questo (senza aggiungere un altro livello di riferimento indiretto)

È comunque possibile ottenere un utilizzo da std::unique_ptr. Se un'interfaccia non cancella un puntatore, è possibile passare in sicurezza in ptr.get(). Se un'interfaccia acquisisce la proprietà della durata di tale oggetto, passa a ptr.release() e rinunci a controllarne la durata da solo.

All in, è possibile ottenere una certa utilità da puntatori intelligenti anche con una base di codice legacy, ma devi essere un po 'cauto.

1

Ma non riesco a verificare se altri metodi in Qt eseguono l'eliminazione dell'operatore sul puntatore memorizzato di scrollArea.

Se il widget ha un genitore, la gestione della memoria del QT rilascerà tale oggetto. In tal caso non è necessario utilizzare un puntatore intelligente, poiché l'applicazione proverà a rilasciarlo due volte e si tratta di un comportamento non definito.