Frage

Warum ist es nicht möglich, ein Verweis auf leere?Das einzige, was ich in der C++ - Standard ist diese Linie, die im 8.3.2.1

Gegen die Feststellung, dass gibt den Typ "Verweis auf cv void" ist schlecht ausgebildet.

Warum ist das so?Warum kann ich nicht schreiben Sie eine "generische" Funktion, die akzeptieren void&?

Nur um klar zu sein, ich habe keine nützliche Anwendung im Sinn, wo mit einem Verweis auf leere könnte besser sein, als die Verwendung von Vorlagen, aber ich bin nur neugierig über die Gründe für ein Verbot dieses Konstrukt.


Um ein wenig zu klären, ich verstehe, dass die Verwendung von Referenz-zu-void "so wie Sie ist" wäre ebenso unsinnig wie die Dereferenzierung Zeiger auf void.Allerdings konnte ich werfe es ein Referenz-zu-sometype um es zu benutzen, konnte ich das nicht?In der Tat, ich sehe nicht, warum der folgende Codeausschnitt kann Arbeit...

void foo(void *data)
{
    int *i = reinterpret_cast<int*>(data);
    // do something with i
}

...während dieses eine nicht:

void foo(void &data)
{
    int &i = reinterpret_cast<int&>(data);
    // do something with i
}
War es hilfreich?

Lösung

Wenn Sie einen Verweis haben für ungültig zu erklären, was würden Sie damit machen? Es wäre nicht eine Zahl oder einen Buchstaben oder einen Zeiger, oder etwas ähnliches sein. Ihre hypothetische generische Funktion auf es eine Operation nicht durchführen konnte, außer unter seiner Adresse (und nicht die Größe).

„Leere“ hat zwei Verwendungen: Kenntnis von Art zu verzichten (wie in void *), und nichts zu geben, im Gegensatz zu etwas (void Funktion zurück). In beiden Fällen ist es möglich, außer etwas über eine Leere, etwas zu sagen, dass er eine Adresse haben kann.

Wenn Sie nicht einen Weg finden, etwas nützlich sein kann, und ich kann nicht, dass zumindest Anzeichen dafür, dass etwas nutzlos ist, und das kann auch zumindest einen Teil der Begründung hier sein.

Andere Tipps

Fragen Sie sich selbst zuerst, wie Sie würde de-reference einen void-Zeiger?

void *p = /*something*/ ;
cout << *p << endl;

Der obige Code ist bedeutungslos, einer der Gründe, warum wir haben nichtig ist, so können wir sagen: „Ich brauche hier einige generische Zeiger Arbeit zu tun, und ich weder weiß noch egal, was ich Hinweis auf“. Per Definition weiß der Compiler nicht, was ein void * Punkte auf, und kann daher nicht dereferenzieren. Sie können - durch Gießen -. Aber der Compiler kann nicht

Ein Verweis auf einen Leere sufferes aus dem gleichen Problem, definitionsgemäß die Daten wiesen auf keinen Typen, und kann daher nicht in sinnvoller Weise referenziert werden.

Um es zu verweisen Sie - der Programmierer - müssen es auf eine andere Art werfen, dann können Sie einen typisierten Verweis darauf haben

.

Nicht sicher, ob ich das so gut erklärt, wie ich wollte.

Ruben, irgendwelche Gedanken?

EDIT:. Ihre Bearbeitung beantworten

Nehmen Sie

die erste Funktion, in der Sie void * Daten übergeben. Daten ist ein perfekt gültiges Element, können Sie mit ihm berechnen, oder wenn Sie einige Protokollierung implementiert haben, können Sie es anmelden.

logger << data;

und Sie werden die Adressdaten Punkte bekommen. Wenn Sie zu dereferenzieren Daten versuchen, gibt den Compiler einen Fehler (nicht C ++ Compiler hat im Moment praktisch, so dass nicht sicher, ob des tatsächlichen Fehlers). z.B.

void* data = /* some assignment */;
logger << *data; // compiler error.

Nun wird der Compiler nicht Sie dereferenzieren einen void * aus irgendeinem Grunde lassen (es ist nicht sinnvoll), die gleiche steht für eine Referenz ungültig zu erklären und Daten, außer dass, weil es eine Referenz ist es implizit dereferenziert die ganze Zeit . Der Compiler wird nicht Sie dereferenzieren eine Lücke lassen * auf eine Operation, es wird nicht ständig Sie dereferenzieren lassen.

void& data = /* some assignment *.;
logger << data; // means same as logger << *data above

Sie können nicht tun ANYTHING , um Daten außer nimmt es Adresse, und es gibt eine ganz gute - und sicher - Methode in die languge gebaut zu tun, dh

void* data;

Ist das mehr Sinn machen?

Eine Referenz ist ein Verweis auf eine Instanz von etwas. Eine Instanz von etwas kann nicht vom Typ void sein. Jede Instanz von etwas muss eine bestimmte Art hat (und möglicherweise Basistypen).

Hier ist eine Übersicht über die verschiedenen Dinge, die gesagt wurden, und dass ich gedacht.

Zwei Hauptgründe, warum Referenz-to-Lücke sind nicht zulässig


1 Sie hätten völlig nutzlos gewesen.

Wenn wir nämlich zu den Zeiten von C zurückblicken, void-Zeiger hatte zwei Aufgaben:

  • Speicherverwaltung (zum Beispiel malloc)
  • Genericity (Schreibfunktionen, die jede Art von Argumenten annehmen kann)

Wenn C ++ herauskam, Vorlagen wurde die beste Lösung Genericity zu implementieren. Allerdings hatte Management individuellen Speichers immer noch möglich sein, und die Interoperabilität zwischen C ++ und C war ein wichtiges Anliegen, so void * keeped wurde. Eine hypothetische Leere Referenz keine Hilfe bei der Speicherverwaltung wäre, und Genericity bereits abgedeckt, so dass im Grunde wäre es so gut wie keine Verwendung hat (mit Ausnahme der Garantie der Nicht-nullness unten beschrieben).

2 Sie würden nicht in der Lage sein, alles zu tun, damit

Wenn Sie einen void-Zeiger verwenden, sind Sie nicht zu dereferenzieren es erlaubt; auf den Fall von Referenzen umgesetzt, bedeutet, dass Sie nicht die (immer hypothetisch) void Referenz verwenden können. So

void *data = // something
// using *data and data-> is forbidden

void &data = // something
// using data is forbidden

Allerdings konnten wir von einem Anwendungsfall denken, wo der Verweis nicht „dereferenziert“ werden müßte (diese Phrase schrecklich falsch ist, aber Sie bekommen meinen Punkt), aber wo wären wir nur seine Adresse. Nehmen wir an, ich habe die folgende Funktion:

void foo(void *dataptr)
{
    assert(dataptr != NULL); // or != 0
    // do something with dataptr
}

dieses lästige assert zu vermeiden, ich könnte die Funktion auf diese Weise schreiben:

void foo(void &dataref)
{
    void *data = &dataref;
    // do something with data
}

Doch dies funktioniert, muss &dataref zu dataptr gleichwertig ist, was nicht der Fall ist : &dataref äquivalent zu &*dataptr!

Daher auch die Adresse unter impliziert eine dereferenzierenden, zumindest vom Konzept her (hinter den Kulissen ist die erste Äquivalenz wohl wahr, aber auf der semantischen Ebene ist es nicht). Folglich gibt absolut keine Verwendung ist, können wir von Daten machen, so nichtig Referenzen sind eine Verirrung.

Technisch gesehen, alle, die garantiert ist, dass eine Referenz auf ein Objekt ist ein alias für es.Dass unter der Haube Referenz-argument übergeben wird getan, mit Zeigern ist eine Implementierung detail.Dies kann verwirrend sein, da der Verweise wiederverwenden von der & - operator ist auch die Adresse,-der, aber beachten Sie, dass der Bediener tatsächlich hat verschiedene Bedeutungen in verschiedenen Kontexten (in einer Variablen-oder Parameterdeklaration es kennzeichnet einen Verweis geben, ansonsten ist es der Adresse -, außer wenn es bitweise und-Verknüpfung).Weil es technisch nur ein alias für ein Objekt, eine Referenz ist "immer dereferenziert' as Worrier erklärt.

OK, ist eine Sache, mit mir über dieses nervt. Die Idee eines void*, wie oben erwähnt, ist, dass Sie immer noch eine gültige Variable enthält eine Adresse haben, aber die Art ignoriert wird. Dies scheint zulässig, da wir nach wie vor mit der Adressdaten arbeiten können - die Art etwas überflüssig ist (oder weniger wichtig) in diesem Zusammenhang. Dereferencing es schlecht ist, weil zu versuchen und zugreifen Mitglied macht keinen Sinn, zum Beispiel p.mem. Wir wissen nicht, welche Klasse, zu beziehen und damit auf den Speicher, der VTable-Zeiger zu springen zu folgen.

Allerdings würde es dann scheint Sinn zu machen, das auf eigenem p wäre OK, da es nur auf das Objekt beziehen würde, aber keinen ihrer Daten. Keine Klasse Informationen benötigt so nur die Adresse zu tun. Ich verstehe es absolut keine Verwendung für diese, aber es ist wichtig, bei der Definition, wenn die Dinge brechen. Unter Berücksichtigung dieses Begriffs, eine C ++ Referenz (ständig dereferenced aber nichts Zugriff), z.B. void& ref = static_cast< &void >(obj) macht auch Sinn, und damit nichtig Referenzen erlauben würde. Ich sage nicht, dass jemand sollte es mit den Verantwortlichen aufnehmen, sondern aus einer Sicht „macht Sinn“, wäre es richtig erscheinen, nicht wahr?

Wie Luc Touraille oben erwähnt (zumindest, das ist meine Interpretation), es umgesetzt werden könnte, aber das Problem ist ein semantischer ein. Die vernünftige Erklärung, die ich kommen konnte, war, dass da eine Objektvariable ein „Tag“ für eine Folge von Speicher ist, die Art des wichtigen semantischen Wertes ist. Somit der Zeiger, wobei Gedanke als eine Variable mit einem Adressenwert, behandelt die Art, wie etwas überflüssig -. Nicht zu definieren, es Taste

Würde jemand mit dem zustimmen?

Sie können als dereferenzierte Zeiger eine Referenz denken. Syntaktisch behandeln Sie eine Referenz, als ob es kein Zeiger ist: Sie müssen nicht den Operator * zu dereferenzieren, und Sie können verwenden. statt. -> Mitglieder zugreifen

Sie können jedoch nicht dereferenzieren einen void Zeiger. Wie der Versuch von Binary Worrier darauf hingewiesen, dass Sie tun einen Compiler-Fehler geben. Und wenn Sie nicht einen dereferenzierte void-Zeiger haben können, das heißt, Sie nicht eine Lücke Bezug haben.

Wenn sie sind, würden sie von Zeigern semantisch nicht unterschieden werden, und syntaktischen Zucker betragen würden. Eine Referenz sagt: „Ich auf etwas beziehen, die von dieser Art ist.“ Zulassen Leere oder NULL-Verweis schwächen würde diesen Unterschied von Zeigern.

Zugegeben, es ist immer noch möglich, dass ein Verweis auf ein Objekt zu verweisen, die nicht mehr existiert, aber das ist eine Ausnahme.

Hier finden Sie nicht eine Verteidigung des Begriffs der Leeren Referenzen. Ich biete es als eine Anekdote aus der Wildnis. Fragen Sie sich, wenn es nicht komisch riecht.

Meine Firma war einer der ersten, unter Verwendung von C ++ im Handel und zunächst Cfront . Frühe Entwickler wurden immer noch lernen, die Sprache, und in der Regel jeden Trick im Buch mit (Betreibern überall!). Hier ist ein Trick, den sie gedacht war cool:

void Foo::something(int action, ostream &os = *(ostream *)0)
{
   ostream *os_p = &os;
   if (&os == (ostream *)0) {
      os_p = &cerr;
   }
   // continue with method
}

Also hier Sie haben, keine Leere Referenz, sondern ein typisierten Verweis mit einem potenziell void Bindung! Ein Moment des Nachdenkens sollte wohl besser Alternativen zu diesem Idiom vorschlagen ...

void ist etwas, das per definitionem nicht existiert, so ist es nicht logisch zu haben, Adresse es ist.

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