auto + const + smart pointer =schlechte Mischung?

auto + const + smart pointer =schlechte Mischung?

const ist eine Funktion, die von C++-Entwicklern seit Jahrzehnten für gute Dienste geschätzt wird, um Code robuster zu machen, indem versehentliche Änderungen verhindert werden.

Smart Pointer gibt es auch schon seit langer Zeit und haben den Lebenszyklus vieler Objekte sowie die Lebensbilanz vieler Entwickler im Laufe der Jahre vereinfacht.

auto ist ein neueres Feature (C++11), das entwickelt wurde, um Code einfacher zu machen, und es wird seit Jahren beworben, damit wir es fast immer verwenden.

Also, wenn wir auto eingeben , const und einem intelligenten Zeiger zusammen, sollten wir erwarten, dass es eine großartige Mischung aus einfachem, robustem und ausdrucksstarkem Code produziert.

Diese Kombination kann jedoch eher zu irreführendem als zu aussagekräftigem Code führen. Wie in Code, der so aussieht, als würde er etwas tun, es aber nicht tut. Und betrügerischer Code ist eine der gefährlichsten Arten von Code.

auto + konstant + Zeiger

Beim Deklarieren eines Objekts mit auto und const impliziert, dass das Objekt tatsächlich const ist :

auto const numbers = std::vector<int>{1, 2, 3, 4, 5};

Der obige Vektor numbers ist const :Wir können nichts hinzufügen, entfernen oder ändern, sonst würde der Code nicht kompiliert. Wenn dieser Vektor als Eingabe gedacht ist, hindert er uns daran, ihn versehentlich zu ändern und einen Fehler zu erzeugen.

Betrachten Sie nun den folgenden Fall:Zuweisen eines Zeigers in einen auto const Wert:

Thing* getSomething();

auto const thing = getSomething();

Wie sieht dieser Code aus? Da steht, dass thing ist const . Aber thing ist ein Zeiger, was bedeutet, dass thing kann auf nichts anderes zeigen als auf getSomething ist zurückgekommen. Dies ist das Äquivalent zu:

Thing* const thing = getSomething();

Der Zeiger ist konstant, aber nicht der Wert, auf den er zeigt.

Aber bei Verwendung von thing Interessieren Sie sich im Geschäftscode wirklich für den Wert des Zeigers? Wenn der Sinn der Verwendung von thing ist es, das Objekt zu erreichen, auf das es zeigt, wie es oft der Fall ist, Sie tun es nicht. Die Rolle von thing soll das Objekt verkörpern, auf das gezeigt wird, und es kommt vor, dass Sie einen Zeiger erhalten, um es zu manipulieren.

Daher sieht es für mich danach aus, dass der Code darauf hindeutet, dass wir einen const manipulieren Thing , und kein const Zeiger auf Thing . Dies ist zwar nicht der Fall, aber beim Lesen von Code überprüfen Sie nicht jeden Prototyp jeder aufgerufenen Funktion. Umso mehr, wenn der Prototyp von getSomething befindet sich nicht in unmittelbarer Nähe (was im Allgemeinen nicht der Fall ist):

auto const thing = getSomething();

Dieser Code schreit, dass Sie durch einen schreibgeschützten thing geschützt sind , während es nur ein schreibgeschützter Zeiger auf ein änderbares Objekt ist. Täuscht es Sie nicht?

Eine Möglichkeit, dieses Problem zu umgehen, könnte darin bestehen, auto const* zu verwenden , um das Objekt, auf das gezeigt wird, const zu machen :

auto const* thing = getSomething();

Oder ist es ein Fall, dass die ungarische Notation zurückkommt?

auto const pThing = getSomething();

Ew, nein, wir mögen die ungarische Schreibweise nicht.

Aber Sie denken vielleicht, wer gibt überhaupt einen rohen Zeiger von einer Funktion zurück? Wir haben sogar die Möglichkeit erwähnt, Rohzeiger aus C++ zu entfernen (okay, es war am 1. April, aber trotzdem kam die Idee nicht aus dem Nichts). Wir sollten jetzt Smart Pointer verwenden, oder?

Richtig, wir sollten. Aber erstens gibt es immer noch veralteten Code, der noch nicht aufgeholt hat, und man kann mit Sicherheit sagen, dass es noch eine Weile dauern wird.

Und zweitens leiden Smart Pointer unter dem gleichen Problem, aber schlimmer. Mal sehen, warum.

auto + konstant + intelligenter Zeiger

Lassen Sie uns die Schnittstelle von getSomething modernisieren und lassen Sie es einen intelligenten Zeiger zurückgeben, um auszudrücken, dass es den Besitz des Objekts an seinen Aufrufer abgibt:

std::unique_ptr<Thing> getSomething();

Unser Aufrufcode sieht so aus:

auto const thing = getSomething();

Auch wenn der Code in Bezug auf die Eigentümerschaft viel robuster ist, in Bezug auf das, was const ist und was nicht, die Situation ist identisch mit der mit rohen Zeigern.

Tatsächlich ist der Smart Pointer im obigen Code const , was uns selten interessiert, aber das Objekt, auf das es zeigt, nicht. Und der Code vermittelt dieses falsche Gefühl des Schutzes, indem er einen vorbeigehenden Leser zu der Annahme verleitet, dass das Objekt, das wirklich vom Code verwendet wird (wahrscheinlich der Thing der intelligente Zeiger zeigt) ist const und dass alles sicher ist.

Was bei intelligenten Zeigern noch schlimmer ist, ist, dass es keine Möglichkeit gibt, Informationen um den auto hinzuzufügen . Mit einem rohen Zeiger könnten wir auf Folgendes zurückgreifen:

auto const* thing = getSomething();

Aber mit einem intelligenten Zeiger können wir das nicht.

In diesem Fall schätze ich, dass die beste Option darin besteht, den const zu entfernen zusammen, um Verwirrung zu vermeiden:

std::unique_ptr<Thing> getSomething();

auto thing = getSomething();

Haben Sie dieses Problem in Ihrem Code festgestellt? Wie sind Sie vorgegangen? Alle Ihre Kommentare sind willkommen.

Das könnte dir auch gefallen

  • Kluge Entwickler verwenden intelligente Zeiger
  • Die beeindruckende const-Referenz, die nicht const ist