Was sind einige der Hauptgründe für die Verwendung von rohen Zeigern im Jahr 2014, angesichts der Tatsache, dass der C ++ 11-Standard jetzt von den meisten anständigen Compilern gut unterstützt wird?
Ich habe ein paar Szenarien identifiziert:
Sie erweitern eine ältere Codebase, die rohe Zeiger stark verwendet, und möchten die Konsistenz im Stil beibehalten.
Sie verwenden eine Bibliothek, die nur rohe Zeiger exportiert, aber ich schätze, Sie könnten immer noch Umwandlungen verwenden.
Sie möchten die Fähigkeit von Zeigern ausnutzen, mehrere Dereferenzierungsebenen bereitzustellen. (Ich kenne C ++ 11 nicht gut genug, um zu wissen, ob dies mit intelligenten Zeigern oder mit anderen Techniken erreicht werden kann.)
Welche anderen Szenarien sind Ihrer Meinung nach für die Verwendung von Zeigern geeignet?
Würden Sie sogar empfehlen, heute über Zeiger zu lernen?
Ich kann mir Umstände vorstellen, unter denen Sie ein statisch zugewiesenes Array haben und einen rohen Zeiger verwenden möchten, um es in Hochleistungscode zu durchlaufen. Es ist immer noch nichts falsch daran.
Ihre # 1 ist wahr.
Ihre # 2 ist möglicherweise nicht richtig: Wenn Sie "Umwandlungen" verwenden, um rohe Zeiger zu konvertieren, die einer Bibliothek eines Drittanbieters gehören, in intelligente Zeiger (was lokalen Besitz bedeutet), dann ist etwas schrecklich schiefgelaufen.
Ihre # 3 ist technisch wahr, aber vermeiden Sie dies, wann immer Sie können.
Was heute nicht empfohlen wird, ist das Spielen mit rohen Zeigern zu Ihrem eigenen, dynamisch zugewiesenen Speicher . Das heißt, der Ratschlag besteht darin, new
ohne Smart Pointer zu vermeiden (und die Folge ist, dass Sie delete
nicht benötigen sollten).
Jeder ist gegen rohe Zeigern, da es viel zu einfach ist, sie zu verlieren.
Aber Sie können rohe Zeiger verwenden, um auf Daten zu verweisen, die sich irgendwo anders befinden ... nur nicht new
/ delete
sie. Verwenden Sie dafür std::unique_ptr
oder std::shared_ptr
. Oder verwenden Sie für dumme (POD) Speicherpuffer std::vector<unsigned char>
, nicht malloc
und free
selbst.
Stellen Sie sich ein std::vector<heavy_object*>
vor, wenn Sie mit Unterauswahlen von Objekten jonglieren müssen, die nicht einfach zu kopieren sind, aber bereits an anderer Stelle existieren. Sie brauchen Zeiger dafür.
Sie brauchen auch Zeiger in Funktionen für optionale Argumente, wo Referenzen sie nicht abschneiden, da Sie nullptr
übergeben können.
Zeiger auf aufeinanderfolgende Objekte können auch leicht ohne iteriert werden. Nur std::iterator
overhead ++
oder --
und das war's. Ich verwende oft direkte Zeiger-Iteration anstelle von begin
, end
für Vektoren.
Wenn du verstehst, wie sie funktionieren ... wirst du sie sehr brauchen und sie werden sie richtig benutzen.
Intelligente Zeiger werden für die Behandlung von Objektbesitzproblemen verwendet, aber nicht alle Zeiger werden verwendet, um mit Objektbesitz umzugehen. Zum Beispiel ist es sinnvoller, einen rohen Zeiger an eine Funktion zu übergeben, wenn Sie nicht vorhaben, das Eigentumsrecht an diese Funktion zu übergeben (d. H. Sie möchten nur, dass die Funktion mit den vom Zeiger adressierten Daten umgeht)
IMHO Raw-Zeiger haben immer noch ihren Platz.
Was C ++ 11 uns gibt, ist die Fähigkeit, die Lebensdauer von rohen Zeigern zu verwalten, so dass wir sie nicht selbst löschen müssen.
Es ist nichts Falsches daran, rohe Zeiger zu verwenden, solange sie von einem intelligenten Zeiger / Zeiger-Manager im richtigen Bereich oder Rahmen verwaltet werden, um sicherzustellen, dass ihre Lebensdauer korrekt ist. Wenn das wahr ist, dann müssen Sie niemals einen rohen Zeiger löschen, und Sie können ihn sicher innerhalb des Umfangs / Rahmens verwenden, während dessen seine Lebenszeit garantiert ist.
Ich würde sagen, wenn möglich, speichern Sie einen rohen Zeiger auf Ihr neues Objekt in einem std::unique_ptr
, wenn seine Lebensdauer von einem bestimmten Bereich / Rahmen gesteuert werden soll. Sobald dies geschehen ist, verwenden Sie den rohen Zeiger innerhalb dieses Bereichsrahmens. Nur nie löschen Sie es;
Manchmal ist es nicht möglich, die Lebensdauer eines neuen Objekts von einem einzelnen Bereich oder Rahmen zu verwalten. In diesem Fall verwenden Sie std::shared_ptr
in jedem Bereich / Frame, der unabhängig die Lebensdauer des neuen Objekts verwalten muss. Dann gibt es innerhalb jedes Bereichs / Rahmens keinen Grund, den rohen Zeiger nicht wie bei der Verwaltung durch std::unique_ptr
zu verwenden.
Es gibt also oft keinen Grund, den Geschwindigkeitsnachteilen von Smartpointern zu begegnen, da eine ihrer Stärken darin besteht, die Lebensdauer des neuen Objekts zu verwalten, um die Gültigkeit des rohen Pointers und die automatische Zerstörung seiner zu gewährleisten Objekt, wenn es nicht mehr benötigt wird.
Es gibt andere Zeiten, in denen ein roher Zeiger nicht geeignet ist.
Zum Beispiel, wenn ein verwalteter Zeiger "Besitz" auf einen anderen Bereich / Rahmen übertragen muss. In diesem Fall müssen Sie den Bereich / Rahmen ändern, der für die Lebensdauer des neuen Objekts verantwortlich ist. In diesen Fällen vermeiden rohe Zeiger wie die Pest!
Welche anderen Szenarien sind Ihrer Meinung nach für die Verwendung von Zeigern geeignet?
Eines der Hauptszenarios, in denen rohe Zeiger verwendet werden, ist, wenn Sie nicht besitzende -Zeiger haben. In der Regel, wenn eine Referenz funktionieren würde, Sie aber die Einschränkungen einer Referenz vermeiden möchten (nicht umsetzbar, nicht kopierbar). Sie könnten in diesen Fällen einen reference_wrapper
-Typ verwenden, aber es ist einfacher, stattdessen einen rohen Zeiger zu verwenden. Smart-Pointer codieren den Besitz (wer das Objekt erstellt und zerstört), wenn also kein Besitz zu verschlüsseln ist (weil es sonst impliziert ist), dann ist ein roher Pointer OK.
Um es klar zu stellen, typische Beispiele für das, was ich gerade erklärt habe, sind Dinge wie:
Aber es ist wichtig zu beachten, dass diese Dinge im Allgemeinen nicht in Schnittstellen vorhanden sein sollten. Im Allgemeinen können Sie rohe Zeiger in Schnittstellen (z. B. Bibliotheksfunktionen und -klassen) ziemlich vollständig vermeiden und sie nur intern, d. H. Im bibliotheksseitigen Code und nicht im benutzerseitigen Code, verwenden. Mit anderen Worten, wenn Sie rohe Zeiger verwenden müssen, verstecken Sie sie weg.
Manchmal werden auch rohe Zeiger für optionale Funktionsparameter angezeigt, in denen Sie nullptr
übergeben können, wenn Sie dieses Ergebnis nicht möchten.
Die Hauptsache, die vermieden werden sollte, und im Allgemeinen vermieden werden kann, ist, dass nackte new
/ delete
den Benutzercode aufruft. Eine typische gute moderne C ++ - Bibliothek (und noch mehr mit C ++ 11) wird keine solchen nackten new
/ delete
-Erscheinungen haben, und das ist eine Tatsache.
Raw-Zeiger sind nicht so sehr ein Problem für sich, was problematisch ist, ist (1) manuelle Speicherverwaltung und (2) Eigentumsverwaltung (was problematisch ist, wenn rohe Zeiger anstelle von intelligenten Zeigern verwendet werden).
Würden Sie sogar empfehlen, heute über Zeiger zu lernen?
Natürlich sollten Sie über Zeiger lernen. Sie sind essentiell für das Verständnis der Programmierung und für das Schreiben von bibliotheksseitigem Code. Raw Pointer sind immer noch in den Eingeweiden einer Menge von Bibliothekscode und dergleichen vorhanden, auch wenn Sie sie nicht sehen.
häufige Gründe, rohe Hinweise von meinem Kopf zu verwenden.