Frage

Dies ist ein vereinfachtes Beispiel der Frage zu verdeutlichen:

class A {};

class B
{
    B(A& a) : a(a) {}
    A& a;
};

class C
{
    C() : b(a) {} 
    A a;
    B b; 
};

So B ist verantwortlich für einen Teil von C. Aktualisierung ich den Code durch Flusen lief und es jammerte über das Referenzelement: Fussel # 1725 . Dies spricht von über Standardkopie und Aufgaben kümmern, die fair genug ist, aber Standardkopie und Zuordnung ist auch schlecht mit Zeigern, so gibt es wenig Vorteil gibt.

Ich versuche immer, Referenzen zu verwenden, wo ich kann, da nackte Zeiger vorstellen uncertaintly über die zum Löschen dieses Zeigers verantwortlich ist. Ich ziehe es Objekte, die von Wert einzubetten, aber wenn ich einen Zeiger benötigen, verwende ich in den Mitgliedsdaten der Klasse auto_ptr, die den Zeiger besitzt, und das Objekt um als Referenz zu übergeben.

Ich würde in der Regel nur einen Zeiger in den Mitgliedsdaten verwenden, wenn der Zeiger null sein könnte oder verändern könnte. Gibt es noch andere Gründe Zeiger über Referenzen für Datenelemente zu bevorzugen?

Ist es richtig zu sagen, dass ein Objekt eine Referenz enthält, nicht übertragbar sein sollte, da eine Referenz nicht einmal initialisiert geändert werden sollte?

War es hilfreich?

Lösung

Referenzelemente vermeiden, weil sie beschränken, was die Implementierung einer Klasse tun können (einschließlich, wie Sie erwähnen, die Umsetzung eines Zuweisungsoperators zu verhindern) und keine Vorteile bieten, was die Klasse zur Verfügung stellen kann.

Beispiel Probleme:

  • Sie sind gezwungen, die Referenz in jedem Konstruktor initialiser Liste zu initialisieren: Es gibt keine Möglichkeit, diese Initialisierung in einer anderen Funktion ausklammern ( bis C ++ 0x sowieso Bearbeiten C ++ jetzt hat Delegieren Konstrukteuren )
  • kann der Verweis nicht null Rebound oder sein wird. Dies kann ein Vorteil sein, aber wenn der Code immer Rebinding ermöglichen geändert werden muss oder für das Mitglied null sein, alle Verwendungen des Elements ändern müssen
  • anders als Zeiger Mitglieder, Referenzen können nicht einfach durch intelligente Zeiger oder Iteratoren ersetzt werden, wie Refactoring erfordern könnte
  • Jedes Mal, wenn eine Referenz verwendet wird, es sieht aus wie Werttyp (. Operator usw.), sondern verhält sich wie ein Zeiger (kann Dangle) - so zum Beispiel Google Style Guide es schreckt

Andere Tipps

Meine eigene Faustregel:

  • ein Referenzelement verwenden, wenn Sie das Leben Ihres Objekts wollen auf das Leben anderer Objekte abhängig sein: es ist eine explizite Art und Weise zu sagen, dass Sie nicht zulassen, dass das Objekt am Leben zu sein, ohne eine gültige Instanz einer anderen Klasse - da keine Zuordnung und die Verpflichtung, die Referenzen der Initialisierung über den Konstruktor zu bekommen. Es ist ein guter Weg, um Ihre Klasse zu entwerfen, ohne irgendetwas davon aus darüber Instanz ist, die Mitglied oder nicht einer anderen Klasse. Sie können nur davon ausgehen, dass ihr Leben auf andere Instanzen verknüpft. Es ermöglicht Ihnen später zu ändern, wie Sie Ihre Klasseninstanz verwenden (mit neuem, als lokaler Instanz, als Klassenmitglied, von einem Speicherpool in einem Manager erzeugt, etc.)
  • Verwenden Sie Zeiger in anderen Fällen : Wenn Sie das Element wollen später geändert werden, verwenden Sie einen Zeiger oder einen const Zeiger sicher sein nur die spitze Instanz zu lesen. Wenn diese Art soll kopierbar sein, Sie können Referenzen ohnehin nicht verwendet werden. Manchmal (zB init ()) müssen Sie auch das Element nach einem speziellen Funktionsaufruf initialisieren und dann haben Sie einfach keine andere Wahl, auf einen Zeiger zu verwenden. ABER: Verwendung behauptet in all Member-Funktion, um schnell falsch Pointer-Zustand zu erkennen
  • In Fällen, in denen Sie die Objektlebensdauer auf einem externen Objekts Lebensdauer abhängig sein wollen, und Sie müssen auch diese Art kopierbar sein, dann Zeiger Mitglieder, sondern Referenz Argument Konstruktor verwenden Auf diese Weise sind Sie auf dem Bau darauf hinweist, dass die Lebensdauer dieses Objekts hängt von der Lebensdauer des Arguments, aber der Zeiger Implementierung Gebrauch noch kopierbar sein. Solange diese Mitglieder nur durch Kopie geändert werden, und Ihre Art hat keinen Default-Konstruktor, sollte der Typ beiden Ziele erfüllen.

Objekte selten sollten assign und andere Sachen wie Vergleich zu ermöglichen. Wenn Sie einige Geschäftsmodell mit Objekten wie ‚Abteilung‘, ‚Mitarbeiter‘, ‚Direktor‘ betrachten, ist es schwer, einen Fall vorstellen, wenn ein Mitarbeiter wird auf andere übertragen werden.

Also für Business-Objekte ist es sehr gut ein Eins-zu-Eins-zu beschreiben und zu einer Eins-zu-viele-Beziehungen als Referenzen und keine Zeiger.

Und wahrscheinlich ist es in Ordnung, Ein-oder-Null-Beziehung als Zeiger zu beschreiben.

Also kein ‚wir können nicht zuordnen‘ dann Faktor.
Viele Programmierer nur mit Zeigern gewöhnen, und das ist, warum sie jedes Argument findet Verwendung von Referenz zu vermeiden.

Mit einem Zeiger als Mitglied werden Sie oder ein Mitglied Ihres Teams zwingen, den Zeiger immer wieder zu überprüfen, vor dem Gebrauch mit „just in case“ Kommentar. Wenn ein Zeiger Null ist, dann ist wahrscheinlich als eine Art Flag Zeiger sein kann verwendet, was schlecht ist, wie jedes Objekt hat ihre eigene Rolle spielen.

In einigen wichtigen Fällen wird Zuordenbarkeit einfach nicht benötigt. Diese sind oft leichte Algorithmus Wrapper, die Berechnung zu erleichtern, ohne den Rahmen zu verlassen. Solche Objekte sind erstklassige Kandidaten für Referenzelemente, da Sie sicher sein können, dass sie immer halten brauchen eine gültig Referenz und nie kopiert werden.

In diesem Fall stellen Sie sicher, den Zuweisungsoperator (und oft auch den Kopierkonstruktor) nicht nutzbare (durch Erben von boost::noncopyable oder erklären sie privat) zu machen.

Wie jedoch Benutzer pts bereits kommentiert, ist für die meisten anderen Objekte nicht wahr. Hier Referenzelemente verwenden, kann ein großes Problem sein, und in der Regel vermieden werden sollte.

Wie jedes Austeilen allgemeine Regeln zu sein scheint, ich werde bieten zwei:

  • Nie, nie Gebrauch Referenzen als Klassenmitglieder verwenden. Ich habe noch nie so in meinem eigenen Code getan (außer mir selbst zu beweisen, dass ich Recht in dieser Regel war) und kann nicht einen Fall vorstellen, wo ich so tun würde. Die Semantik ist zu verwirrend, und es ist wirklich nicht, welche Referenzen für entworfen wurden.

  • Immer, immer, Referenzen verwenden, wenn Parameter an Funktionen, mit Ausnahme der grundlegenden Typen vorbei, oder wenn der Algorithmus erfordert eine Kopie.

Diese Regeln sind einfach und haben mich in der guten Stelle stand. Ich lasse machen Regeln zur Verwendung von Smart Pointer (aber bitte, auto_ptr nicht) als Klassenmitglieder an Dritte weiter.

Ja zu: Ist es richtig zu sagen, dass ein Objekt eine Referenz enthält, nicht übertragbar sein sollte, da eine Referenz nicht einmal initialisiert geändert werden sollte

Meine Faustregeln für Datenelemente:

  • nie eine Referenz verwendet werden, da es Zuweisung verhindert
  • , wenn Ihre Klasse ist verantwortlich für das Löschen Verwendung boost des scoped_ptr (die sicherer ist als ein auto_ptr ist)
  • sonst, verwenden Sie einen Zeiger oder const Zeiger
  

Ich würde in der Regel nur einen Zeiger in den Mitgliedsdaten verwenden, wenn der Zeiger null sein könnte oder verändern könnte. Gibt es noch andere Gründe Zeiger über Referenzen für Datenelemente zu bevorzugen?

Ja. Lesbarkeit des Codes. Ein Zeiger macht es offensichtlich, dass das Mitglied eine Referenz (ironisch :)), und nicht ein Objekt enthalten, denn wenn Sie es verwenden, müssen Sie de-reference es. Ich weiß, dass einige Leute denken, dass ist altmodisch, aber ich denke immer noch, dass es einfach Verwirrung und Fehler zu vermeiden.

Ich rate Referenzdatenelemente becasue wissen Sie nie, wer aus Ihrer Klasse abzuleiten geht und was könnten sie tun wollen. Sie wollen vielleicht nicht Gebrauch des referenzierten Objekts machen, aber eine Referenz Sie haben sie gezwungen, ein gültiges Objekt zur Verfügung zu stellen. Ich habe dies selbst getan genügend Mitglieder mit Referenzdaten zu stoppen.

Wenn ich verstehe die Frage richtig ...

Referenz als Funktionsparameter statt Zeiger: Wie Sie wies darauf hin, ist ein Zeiger nicht deutlich machen, wer die Bereinigung / Initialisierung des Zeigers besitzt. Bevorzugen Sie einen gemeinsamen Punkt, wenn Sie einen Zeiger wollen, ist es ein Teil von C ++ 11 und eine weak_ptr, wenn die Gültigkeit der Daten nicht durch die gesamte Lebensdauer der Klasse garantiert wird, um die spitzen, um Daten zu akzeptieren .; auch ein Teil der C ++ 11. eine Referenz als Funktionsparameter unter Verwendung gewährleistet, dass der Verweis nicht null ist. Sie haben die Sprachfunktionen zu unterlaufen, dies zu umgehen, und wir kümmern uns nicht um lose Kanone Coder.

Referenz einer Membervariable: Wie oben in Bezug auf die Gültigkeit der Daten. Dies garantiert die spitzen auf Daten, dann verwiesen, gültig ist.

Umzug Verantwortung variabler Gültigkeit zu einem frühen Punkt in dem Code nicht reinigt nur den späteren Code auf (die die Klasse A in Ihrem Beispiel), sondern macht es auch klar auf der Person verwendet wird.

In Ihrem Beispiel, das ist ein bisschen verwirrend (ich würde wirklich versuchen, eine klarere Umsetzung zu finden), die A von B verwendet wird für die gesamte Lebensdauer des B garantiert, da B Mitglied von A ist, so dass ein Referenz verstärkt diese und (vielleicht) mehr klar.

Und für alle Fälle (die eine geringe Wahrscheinlichkeit Haube ist, wie es keinen Sinn in Ihren Codes Kontext machen würde), eine weitere Alternative, ein nicht Bezug genommen wird, nicht Zeiger Parameter zu verwenden, A würde kopieren, und das Paradigma machen nutzlos. - ich Sie glaube nicht, dass dies bedeutet, als Alternative wirklich

Auch dies auch garantiert nicht in der Lage ist, die Daten zu ändern, verwiesen, wo ein Zeiger geändert werden kann. Ein const Zeiger funktionieren würde, nur dann, wenn das referenzierte / Zeiger auf Daten war nicht wandelbar.

Zeiger sind nützlich, wenn der A-Parameter für B nicht gesetzt werden sollte, wurde garantiert, oder neu zugewiesen werden könnte. Und manchmal ein schwacher-Pointer ist einfach zu ausführlich für die Umsetzung und eine gute Anzahl von Menschen entweder nicht wissen, was ein weak_ptr ist, oder sich einfach nicht mögen.

Sie diese Antwort Zerreißen, bitte:)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top