- Registriert
- 1 Aug. 2013
- Beiträge
- 235
Ich kann nachvollziehen, wo die Aussage herkommt. Ich halte sie trotzdem für falsch. Da spricht der C-Programmierer, der mit der Erfahrung und den Annahmen aus seiner Welt auf C++ blickt. Und der sieht erstmal »C with Classes«, aber das ist von C++ weit entfernt.theSplit schrieb:Und es gibt eine Aussage, ja da fühle ich genau mit:
"References are of course valuable , but i come from C , where pointers are everywhere. One has to be proficient with pointers first to understand the value of references."
Eines muss ich dazu glaub ich mal ausdrücklich sagen: Ich rede immer von C++ im Jahr 2017, so wie ich C++ in einem heute brandneu aufgesetzten Projekt benutzen würde. Also mit allem, was C++14 hergibt, mit zunehmend weniger Zurückhaltung bei C++17 – weil’s so gut wie fertig und in den großen Compilern gut implementiert ist –, und ohne Rücksicht auf irgendwelche Legacy-Überlegungen. Außerdem hab ich immer v.a. die Entwicklung einer Otto-Normal-Enduser-Applikation im Kopf – im Gegensatz zur (Standard-)Library-Entwicklung und zur hardwarenahen Low-Level-Programmierung (z.b. Treiber). Vielleicht liegen die Dinge dort anders, vielleicht auch nicht. Ich stecke in den Gebieten zu wenig drin, um wirklich fundiert was dazu sagen zu können.
Zurück zu dem Punkt, auf den ich raus wollte. In C sind Pointer ein alltägliches, überall verwendetes Tool. C++-Pointer sind technisch im Großen und Ganzen dasselbe. Deswegen ist es verführerisch davon auszugehen, dass sie auch genauso verwendet werden. Ist aber nicht so. Pointer in C++ sind hauptsächlich notwendig als Handles für heap-allokierte Objekte – dann meistens gewrappt als Smartpointer. Davon abgesehen ist ein Pointer ein Spezialtool, das man vergleichsweise selten sieht; massiv seltener als in einer C-Codebasis.
Es gibt das beliebte Zitat: »Referenzen sind Pointer, die nicht null sein können«. Vordergründig hemdsärmelig kommt man damit beim Coden erstmal ganz schön weit. Aber es vermittelt ein reichlich schräges Bild von Referenzen. Auf den Punkt gebracht:theSplit schrieb:Gibt es einen konkreten Unterschied zwischen einer "Referenz" und einem Pointer in C++?
Ein Pointer ist eine typisierte Speicheradresse. Er ist eine Entität mit eigenem Inhalt – eben die Adresse.
Eine Referenz ist ein alternativer Name für ein Objekt. Sie hat keine eigene Identität und damit auch keinen eigenen Inhalt. Schau mal im Vergleich:
[src=cpp]#include <string>
// Typ-Alias
using StringType = std::string; // bevorzugte Form
typedef std::string StringType2; // alte Form, tut dasselbe
// Wert-Alias
int foo = 42;
int& bar = foo;
// aber
int* ptr = &foo;
int* ptr2 = &bar;
assert(ptr == ptr2); // true[/src]
Der Typ-Alias mit using/typedef ist klar, nicht? Der gibt einem existierenden Typen einen zusätzlichen Namen. Es entsteht dabei aber kein neuer Typ. Eine Referenz ist das gleiche, nur mit Werten anstatt mit Typen. Die Variable, in der der Wert 42 gespeichert ist, kann wahlweise als foo oder bar angesprochen werden. Es ist aber ein und diesselbe Variable. Es gibt nichts eigenes Greifbares, das die Referenz darstellt. Im Gegensatz dazu ptr. Da gibt es etwas Greifbares, nämlich die Pointervariable, die die Speicheradresse von foo/bar enthält.
So, einmal sacken lassen, bitte. Kaffee holen. Und dann weiter. Wo das mit der Referenz als »Nicht-Null-Pointer« vermutlich herkommt, ist ein Implementierungsdetail im Compiler. Hinter den Kulissen – also Richtung Objektcode/Assembler – sind Referenzen nämlich üblicherweise als Pointer implementiert. Das ist aber ein reines Compilerdetail. Mit der C++-Sprache hat das nichts mehr zu tun.
Und noch ein bisschen Refs in der freien Wildbahn:
[src=cpp]
int muh = 42;
int miau = 23;
int& meff = muh;
// Referenzen können nicht umgesetzt (re-seated) werden.
meff = miau;
assert(muh == 23); // true
// Wir hätten mit demselben Effekt auch schreiben können:
muh = miau;
// zurück zur Ausgangslage
muh = 42;
// Refs *müssen* direkt initialisiert werden.
int& puff; // compilation error
// folgende zwei Zeilen haben denselben Effekt
int muh_copy = meff;
int muh_copy2 = muh;
// Hey, die Variable mit der 42 kriegt einen dritten Namen!
// Weil es keine Refs auf Refs gibt.
int& wuff = meff;
[/src]
Der GotW #94 hat einige gut nachvollziehbare Argumente. In template-lastigem Code ist es angenehm, auto zu schreiben und den Compiler den Typen ausklamüsern zu lassen. In dem Sinn ist auto eine schönere Variante, »hiding type« zu betreiben. Vieles davon ging auch vor C++11, war aber deutlich hässlicher – v.a. wenn man es an derselben Stelle mit vielen verschiedenen Typen zu tun haben könnte.BurnerR schrieb:Das [AAA] ist auch so ein bisschen am Rand meiner Erfahrungswelt mit C++, vielleicht kann Brother John ja etwas erhellen
Andererseits ist der GotW #94 jetzt auch schon 4 Jahre alt, und vermutlich würde auch Sutter heute AAA nicht mehr in der Extremheit unterschreiben.
Auf der Anwendungsenticklungsseite muss ich wieder an die Typen von Containeriteratoren denken, z.B. std::vector<T>::begin(). Der zentrale Punkt beim Interface dieser Funktion ist, dass ich einen Iterator (aufs erste Element) in die Hand kriege. Alle Iteratoren funktionieren gleich, deswegen ist mir der exakte Typ von diesem Iterator auch ziemlich wurscht. Er enthält keine nützliche Information. Und dann nehm ich die bessere Lesbarkeit mit auto gern mit.
Zuletzt bearbeitet: