Lieber eine C ++ - Referenz oder ein weak_ptr zurückgeben?

8

Angenommen, ich habe eine Klasse, in der der Benutzer einen Verweis auf eines meiner Mitglieder haben soll. Welches ist bevorzugt?

%Vor%

oder

%Vor%

Was denkst du? Wann ist einer besser als der andere?

    
Doug T. 18.10.2008, 18:39
quelle

9 Antworten

12

Warum gibst du nicht shared_ptr<> zurück? Auf diese Weise kann der Client die zurückgegebenen Daten so lange verwenden, wie er benötigt wird. Es gibt jedoch kein Problem, wenn die Klasse "Server" nicht mehr verfügbar ist.

Es gibt nicht viele Situationen, in denen die Semantik von weak_ptr<> sehr sinnvoll ist (Caches und ???). Wenn ein Kunde nach etwas fragt, möchte er in der Regel Besitz an dem vom Kunden selbst bestimmten Ding haben (und das gemeinsame Eigentum ist genauso gut wie das volle Eigentum).

Wenn Sie eine Situation haben, in der das "Server" -Objekt ohne Kenntnis des Clients zerstört werden kann (eine Situation, in der Sie use weak_ptr<> oder shared_ptr<> verwenden möchten), können Sie eine Referenz auf die schlechteste Sache zurückgeben ein Mitglied. In diesem Fall kann der Client nicht wissen, ob der Zugriff auf die zurückgegebene Referenz sicher ist oder nicht. Sie müssen eine Kopie des Members oder einen Smart-Zeiger zurückgeben, der die Lebensdauer des zurückgegebenen Elements korrekt verwalten kann.

Beachten Sie, dass in dem Fall, in dem ein Ausdruck ein temporäres ClassWithCppReference erzeugt (was nicht immer offensichtlich ist), der Client, der GetMember() aufruft, nicht in der Lage ist, den zurückgegebenen Verweis in der nächsten Anweisung zu verwenden.

    
Michael Burr 18.10.2008 18:57
quelle
4

Sie sollten Ihre Interna nicht verschenken; es ist die Leitlinie n. 42 von "C ++ Codierstandards" (Herb Sutter und Andrei Alexandrescu). Wenn Sie aus irgendeinem Grund besser eine const-Referenz und keinen Zeiger zurückgeben müssen, weil sich die -Konstante nicht durch sie ausbreitet.

weak_ptr & lt; & gt; scheint eine praktikable Lösung zu sein, auch wenn ihr Hauptzweck darin besteht, Zyklen von shared_ptr zu vermeiden. Wenn Sie stattdessen shared_ptr & lt; & gt; Sie verlängern das Leben von solchen internen, die in den meisten Fällen keinen Sinn ergeben.

Das Problem mit der Instanz, die verschwindet, während jemand einen Verweis auf seine Interna bearbeitet, sollte mit einer korrekten Synchronisation / Kommunikation zwischen Threads konfrontiert werden.

    
Nicola Bonelli 18.10.2008 19:14
quelle
4

Ich möchte etwas zu den Kommentaren (vor allem OP und Colomon) über die Effizienz usw. sagen. Oftmals spielt es keine Rolle, ob das Kopieren von Inhalten wirklich wichtig ist, und zwar in Bezug auf die tatsächliche Leistung.

Ich habe Programme geschrieben, die eine Menge defensives Kopieren Es ist ein Idiom in Java, wo, weil alle Objekte mit dem Zeiger übergeben werden, viel Aliasing stattfindet, also kopieren Sie alles, was in Ihre Klasse hinein- und herausgeht, um das Aliasing zu brechen, um sicherzustellen, dass Clients Ihrer Klasse Ihre Klasseninvarianten nicht verletzen können indem Sie ein Objekt nachträglich ändern.

Die Programme, die ich geschrieben habe, haben defensiv ganze Strukturen an Orten kopiert, einschließlich ganzer Listen und Karten. Um sicher zu sein, dass die Leistung nicht beeinträchtigt wird, habe ich das Programm ausführlich beschrieben. Die hauptsächlichen Engpässe waren woanders (und selbst dann habe ich diese anderen Stellen so eingestellt, dass der größte Engpass das Netzwerk ist). Nirgends ist diese defensive Kopie in die Hotspots des Programms eingegangen.

ETA: Ich habe das Bedürfnis, den Sinn meiner Botschaft zu klären, da ein Kommentator es anders liest als ich es beabsichtigt habe, und möglicherweise auch andere es getan haben. Mein Punkt ist nicht, dass es in Ordnung ist, Zeug um Willy-Nilly zu kopieren; aber man sollte immer die Leistung ihres Codes profilieren, anstatt wild zu erraten, wie es funktioniert.

Wenn das Kopieren ganzer Strukturen immer noch akzeptable Leistung bringt und gleichzeitig den Code einfacher zu schreiben macht, dann ist das meiner Meinung nach ein besserer Kompromiss (in den meisten Fällen) als Code, der nur geringfügig schneller ist, aber viel mehr kompliziert.

    
Chris Jester-Young 18.10.2008 21:07
quelle
2

Ich denke, die einzig vernünftige Antwort ist, dass es darauf ankommt, wie Member mit der Klasse verwandt ist und was die Benutzer der Klasse tun sollen. Hat _member eine sinnvolle Existenz, die unabhängig vom Klassenobjekt ist? Wenn nicht, dann glaube ich nicht, dass die Verwendung von shared_ptr sinnvoll ist, egal ob Sie eine weak_ptr oder eine shared_ptr zurückgeben. Im Wesentlichen würde entweder der Benutzer Zugriff auf ein Member-Objekt erhalten, das das Klassenobjekt überleben könnte, das ihm Bedeutung gibt. Das könnte einen Absturz verhindern, aber auf Kosten eines schwerwiegenden Entwurfsfehlers.

Wie awgn angibt, sollten Sie sehr vorsichtig sein, wenn Sie Ihre Klasseninterna offen legen. Aber ich denke, da ist definitiv ein Platz dafür. Zum Beispiel habe ich eine Klasse in meinem Code, die ein Dateiobjekt darstellt, das aus einem Dateikopfobjekt und einem Dateidatenobjekt besteht. Eine vollständige Duplizierung der Header-Schnittstelle in der Dateiklasse wäre albern und würde DRY verletzen. Sie könnten, denke ich, den Benutzer zwingen, eine Kopie des Header-Objekts zu erhalten, die Änderungen an der Kopie vorzunehmen und dann das externe Objekt wieder in die gesamte Dateiklasse zu kopieren. Aber das führt zu einer Menge Ineffizienz, die Ihnen nur die Möglichkeit einräumt, die Dateiobjektdarstellung des Headers anders als die Headerobjektdarstellung zu machen. Wenn Sie sicher sind, dass Sie das nicht möchten, können Sie auch einen nichtkonstanten Verweis auf den Header zurückgeben - das ist einfacher und effizienter.

    
Sol 18.10.2008 20:52
quelle
1

Das Zurückgeben eines schwachen Zeigers ist definitiv kostspieliger und dient keinem wirklichen Zweck - Sie können sich sowieso nicht länger als das Leben des Hauptobjekts am Eigentum festhalten.

    
Jimmy J 22.03.2009 00:04
quelle
1

Warum einen schwachen Zeiger zurückgeben? Ich denke, Sie machen es komplizierter, ohne dass es notwendig ist.

    
Brock Woolf 22.03.2009 00:06
quelle
0

Meine grundlegende, unwissende Richtlinie:

Ich nehme an, dass letzteres unsicher sein kann, wenn die Instanz von ClassWithCppReference weggehen kann, während jemand noch einen Verweis auf ein Mitglied hat. Allerdings kann ich auch ein Argument für die letztere Klasse mit POD-Typen sehen, wie zum Beispiel eine Nachricht an ein Gerät, und Sie wollten das Mitglied nicht die ganze Zeit kopieren.

    
Doug T. 18.10.2008 18:40
quelle
0

In den meisten Situationen würde ich

bereitstellen %Vor%

Der Grund dafür ist, dass (auch ich und wahrscheinlich viele andere) die Methode GetMember() aufrufen, dass Class besitzt member und daher die zurückgegebene Referenz wird nur für die Lebensdauer des enthaltenen Objekts gültig sein.

In den meisten (aber nicht allen) Codes, die mir begegnet sind, werden GetMember() -Methoden im Allgemeinen verwendet, um Dinge mit dem zurückgegebenen Mitglied sofort zu erledigen und nicht für spätere Benutzer zu speichern. Wenn Sie Zugriff auf das Mitglied benötigen, können Sie es jederzeit jederzeit aus dem enthaltenen Objekt anfordern.

    
Tobias 22.07.2009 11:53
quelle
-1

Je nach Kontext könnte beides in Ordnung sein. Das Hauptproblem beim Zurückgeben einer "Live" -Verbindung zu einem Mitglied (wenn Sie eine Person zuerst aufdecken müssen) ist, dass derjenige, der das exposed-Mitglied verwendet, länger daran festhält, als das enthaltene Objekt existiert. Und wenn Ihr Client über eine Referenz auf dieses Mitglied zugreift, wenn sein enthaltendes Objekt den Gültigkeitsbereich verlässt, werden Sie mit "merkwürdigen" Abstürzen, falschen Werten und ähnlichem Spaß konfrontiert. Nicht empfohlen.

Zurückgeben des weak_ptr & lt; & gt; hat den großen Vorteil, dass es dem Client mitteilen kann, dass das Objekt, auf das sie zugreifen, nicht mehr existiert, was die Referenz nicht kann.

Mein Wert von 2 Pfennigen wäre:

  • Wenn keiner Ihrer Kunden jemals das Mitglied verwenden würde, sind Sie als Autor die einzige Person, die davon Gebrauch macht und die Lebensdauer des Objekts kontrolliert. Die Rückgabe eines Verweises ist in Ordnung. Const Referenz wäre noch besser, aber das ist in der realen Welt mit vorhandenem Code nicht immer möglich.
  • Wenn jemand anders auf das Mitglied zugreift und es verwendet, insbesondere wenn Sie eine Bibliothek schreiben, geben Sie den Wert "weak_ptr & lt; & gt;" Es wird Ihnen viel Kummer ersparen und das Debuggen einfacher machen.
  • Ich würde kein shared_ptr & lt; & gt; zurückgeben. Ich habe diesen Ansatz gesehen und wird normalerweise von Leuten favorisiert, die sich mit dem Konzept einer schwachen_ptr / schwachen Referenz nicht wohl fühlen. Der Hauptnachteil, den ich damit sehe, ist, dass es die Lebensdauer des Elements eines anderen Objekts künstlich über den Umfang seines enthaltenen Objekts hinaus verlängert. Das ist konzeptionell falsch in 99% der Fälle und schlimmer, kann Ihren Programmierfehler (Zugriff auf etwas, was nicht mehr da ist) in einen konzeptionellen Fehler (Zugriff auf etwas, das nicht mehr sein sollte sein).
Timo Geusch 19.10.2008 14:46
quelle

Tags und Links