2013-05-21 8 views
13

Ich möchte C++ 11 Smart Pointer in neuen Projekten verwenden und auf ein Problem stoßen. Viele aktuelle Projekte verwenden immer noch rohe Zeiger als Parameter in ihrer Schnittstelle und haben keine Schnittstelle für intelligente Zeiger, z. QMainWindow::setCentralWidget.Gibt es eine sichere Möglichkeit, C++ 11 Smart Pointer und die Schnittstelle für Raw Pointer zusammen zu verwenden?

Um Typen konsistent zu halten, ich habe die gespeicherten Zeiger von get() wie dieses Segment zu übergeben:

QMainWindow win; 

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

win.setCentralWidget(scrollArea.get()); 

Aber ich sicher, ob andere Methoden in Qt ausführen Operator delete auf dem gespeicherten Zeiger von scrollArea machen kann .

Wird es Speicherverlust oder andere Probleme verursachen, wenn einige Methoden in Qt das tun?

Ich habe die neuesten C++ Standard CD überprüft und nichts dazu gefunden. Scheint, es ist ein undefiniertes Verhalten.

Wenn dies ein undefiniertes Verhalten und gefährlich ist, gibt es eine sichere Möglichkeit, intelligente Zeiger mit der Schnittstelle für rohe Zeiger (s) zu verwenden?

+2

Wenn Sie sich nicht sicher sind, ob Qt "delete" ausführt, wie stellen Sie sicher, dass derzeit keine Speicherlecks vorhanden sind? – hmjd

+2

Es ist das gleiche, als wenn Sie gefragt würden "Wird ein Zeiger zweimal gelöscht, um einige Probleme zu verursachen?" –

+0

@ W.B. Mein Hauptzweck ist es, eine Lösung für diesen Fall zu finden. – UniversE

Antwort

16

Es gibt keine solche Art und Weise im allgemeinen Fall. Für jede "Legacy" -Schnittstelle, die Sie verwenden möchten, müssen Sie die zugehörige Dokumentation lesen, um zu sehen, wie sie mit dem Eigentumsrecht interagiert (was std Smartpointer einkapselt). Ein einzelnes Objekt kann nur von einem Eigentumsschema verwaltet werden.

Mit Qt insbesondere ist es definitiv nicht sicher zu mischen, intelligente Zeiger und Qt-Management. Qt Eltern/Kind-Beziehung zwischen QObject s beinhaltet Eigentums Semantik (Kinder werden gelöscht, wenn ihre Eltern ist), so können Sie dies nicht sicher mischen mit jedem anderen Eigentum Schema (wie std intelligente Zeiger).

Beachten Sie, dass die Qt-Dokumente, die Sie verknüpfen, explizit angeben, dass "QMainWindow Besitzer des Widgets Zeiger und löscht es zur entsprechenden Zeit."

3

Leider, wenn Sie eine Schnittstelle verwenden, die Roh-Zeiger verwendet, müssen Sie die Dokumentation konsultieren, um zu bestimmen, ob die Methode funktioniert oder nehmen Sie nicht das Eigentum der bereitgestellten Zeiger.

Wenn die Funktion Besitz nimmt, dann müssen Sie .release() aufrufen, um den Besitz an die Funktion zu übertragen. Wenn die Funktion keine Eigentumsrechte übernimmt, übergeben Sie das Objekt mit .get().

3

Wird es Speicherverlust oder andere Probleme verursachen, wenn einige Methoden in Qt das tun?

Es wird kein Speicherleck eingeführt, da der Speicher überhaupt freigegeben wird. Da jedoch beide QT und die shared_ptrdelete auf diesem Speicher nennen würden, würden Sie wahrscheinlich ein paar nette Heapbeschädigung (UB im Allgemeinen) erhalten.

Gibt es eine sichere Möglichkeit, intelligente Zeiger mit der Schnittstelle für rohe Zeiger zu verwenden?

Sicher. Lassen Sie nicht voneinander unabhängige Entitäten denselben Speicher verwalten.Dafür ist es ratsam, unique_ptr anstelle von shared_ptr zu verwenden, wenn dies möglich ist. Mit unique_ptr können Sie .release() anrufen, um den Speicher von der Kontrolle des smartpointer freizugeben, so dass Sie die Kontrolle über QT geben können.

Natürlich müssen Sie die Dokumentation überprüfen, um zu sehen, wenn Sie Speicher selbst verwalten müssen und wenn QT es für Sie tun wird.

3

Wenn Sie eine Schnittstelle verwenden, die rohe Zeiger verwendet, haben Sie bereits das Problem, dass Sie wissen müssen, wer für die Lebensdauer dieser Zeiger verantwortlich ist.

Das Hinzufügen von shared_ptr in die Mischung ändert dies nicht. Wenn die Schnittstelle das Objekt möglicherweise löscht, können Sie std::shared_ptr nicht sicher verwenden. std::shared_ptr muss die Lebensdauer seiner Objekte steuern und es gibt keinen Weg um diese (ohne Hinzufügen einer anderen Ebene der Indirektion)

Sie können jedoch einige Verwendung von std::unique_ptr bekommen. Wenn eine Schnittstelle keinen Zeiger löscht, können Sie ptr.get() sicher übergeben. Wenn eine Schnittstelle die Lebensdauer dieses Objekts übernimmt, geben Sie ptr.release() ein und Sie geben die Lebensdauer nicht mehr selbst auf.

All-in, können Sie einige Vorteile aus Smart-Zeigern sogar mit einer älteren Codebasis erhalten, aber Sie müssen ein wenig vorsichtig sein.

1

Aber ich kann nicht sicherstellen, ob andere Methoden in Qt Operator löschen auf dem gespeicherten Zeiger von scrollArea ausführen.

Wenn das Widget ein Elternteil hat, wird die QT-Speicherverwaltung dieses Objekt freigeben. In diesem Fall dürfen Sie keinen intelligenten Zeiger verwenden, da Ihre Anwendung versucht, sie zweimal freizugeben, und dies ist ein undefiniertes Verhalten.