• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

C++ Pointerarray wie anlegen?

Brother John

(schein)heilig
Veteran

Registriert
1 Aug. 2013
Beiträge
235
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."
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.

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.

theSplit schrieb:
Gibt es einen konkreten Unterschied zwischen einer "Referenz" und einem Pointer in C++?
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:

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]

BurnerR schrieb:
Das [AAA] ist auch so ein bisschen am Rand meiner Erfahrungswelt mit C++, vielleicht kann Brother John ja etwas erhellen
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.

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:

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
  • Thread Starter Thread Starter
  • #22
Ein Knaller diese Erklärungen.... :)

Ich glaube den Unterschied zu einer Referenz und einem Pointer in gewisser Weise nachvollziehen zu können:

Wenn ich richtig verstanden haben sind Referenzen "Aliase" / Synonyme für bestehende Werte oder Typen, die auf etwas zeigen, ohne dabei die zusätzliche Funktionalität eines Pointer zu haben, sprich kein direkter "null"/"nullptr" Vergleich - weil sie immer auf etwas zeigen müssen, außer ich weise dem Wert "null"/"nullptr" explizit zu?
Die Pointerarithmetik funktioniert daher auch nicht, da eine Referenz nicht wie ein Pointer behandelt werden kann und anders "angesprochen" wird. (Dazu komme ich gleich mal mit einer Frage);

Okay, wenn das so weit stimmt, glaube ich den Unterschied verstanden zu haben.

Extra große Frage mal in den Raum geworfen, und wer jetzt noch nicht komplett verwirrt ist..., würde das hier "theoretisch" gültig sein? Oder würde es nicht kompilieren?

[src=cpp]int* ptr = malloc(sizeof(int) * 2); // Es ist C, ich weiß....
int* ptr2 = &ptr;
int& refPtr = ptr; // Fehler beim compilieren?

++refPtr; // angelangt? Möglich oder Fehler?
++ptr2;

assert(refPtr == ptr2) // = true??

free(ptr); // Speicher freigeben
[/src]

Und da wir davon ausgehen das wir einer Variable ein "Alias" bzw. Synonym geben, sollte das ja lüppen? :unknown:

Nur ist die Frage, ist "refPtr" die Referenz auf einen Pointer oder wäre refPtr nur(!) in der Lage die Adresse des Wertes aufzunehmen, auf die "ptr" ursprünglich gezeigt hat, wenn "int& refPtr = &ptr" nur compiliert? :D
 

exomo

NGBler

Registriert
1 Aug. 2015
Beiträge
129
außer ich weise dem Wert "null"/"nullptr" explizit zu?
Außer durch geschicktes Ausnutzen von * und & ist das gar nicht möglich. Eine Referenz verhält sich ganz genau so wie die original Variable. (Siehe dazu das Beispiel unten)

Das ist auch ein Grund warum ich Referenzen vor Pointern bevorzuge: Keine abstruse Syntax mit Pfeiloperatoren, Sternchen und dereferenzieren usw.

Extra große Frage mal in den Raum geworfen, und wer jetzt noch nicht komplett verwirrt ist..., würde das hier "theoretisch" gültig sein? Oder würde es nicht kompilieren?
Einfach ausprobieren. Aber nein, es kompiliert nicht. Weder theoretisch noch praktisch. Ich habe mal ein bisschen mit deinem Beipiel gespielt:
(würde mit malloc genauso gehen, ich habe das nur ersetzt damit ich keine C Header einbinden muss)
[src=cpp] int* ptr = new int[2]; // für das Beispiel gleichwertig zu malloc
int** ptr2 = &ptr; // ptr2 ist ein "pointer to pointer"
int& refPtr = *ptr; // Einer Referenz einen Pointer zuweisen geht nicht, aber man kann den pointer dereferenzieren
int*& ptrRef = ptr; // Oder du machst eine Referenz auf den Pointer

++refPtr; // Erhöht den int im Array (ptr[0])
++ptrRef; // Das erhöht ptr, da ptrRef ein alias ist, ptr zeigt also auf das 2. Element des Arrays
++ptr2; // erhöht den pointer-pointer, zeigt dann auf ungültigen Speicherbereich

// assert(refPtr == ptr2); // unterschiedliche typen, nicht möglich

// delete[] ptr; // Speicher freigeben, !!! ptr wurde verändert, Laufzeitfehler !!!
--ptr;
delete[] ptr; // Speicher freigeben

// !!! die Referenz refPtr ist damit auch "ungültig"[/src]
 

Brother John

(schein)heilig
Veteran

Registriert
1 Aug. 2013
Beiträge
235
Thx, exomo! Hätte ich nicht besser sagen können. Lass mich eins nochmal betonen:
exomo schrieb:
// !!! die Referenz refPtr ist damit auch "ungültig"
Weil das echt wichtig ist. Es gibt zwar keine Nullreferenzen; aber »dangling references«, die gibt’s genauso wie »dangling pointers«.

@theSplit, drfuture
Vielen Dank für die Blumen! … verdammt, jetzt hab ich den Tom&Jerry-Titelsong im Ohr. :D

Oh, einen C/C++-Unterschied hab ich noch, weils so schön passt. Es gibt in C++ keinen impliziten Cast von void* zu irgendwas. Die malloc-Zeile müsste also so aussehen, damit sie baut:
Code:
int* ptr = static_cast<int*>(malloc(sizeof(int) * 2));
 

Roin

Freier Denker

Registriert
22 Juli 2013
Beiträge
581
Da habe ich doch auch direkt noch eine kleine Frage:

[src=cpp]vector<connection*> getConnections() {
return connections;
}

// --- Gegenvorschlag ---
const vector<connection*>& getConnections() {
return connections;
}
[/src]

Ich habe zwar schon gesehen, dass man auch eine Referenz als Rückgabewert einer Funktion haben kann, allerdings habe ich es bisher nur verwendet, wenn beispielsweise eine Member-Variable meiner Klasse (zum Beispiel ein Vector) zurückgegeben werden sollte.
Nun ist meine Frage: Kann ich auch Referenzen auf neue Variablen zurückgeben, ohne dass das verlassen des Scopes es mir kaputt macht?
Beispiel:

[src=cpp]
const std::vector<std::string>& getCoolStringVector() {
vector<std::string> ret
for(int i = 0; i != 10; i++)
ret.push_back(std::to_string(i) + "_Zahl");
return ret;
// exiting the scope of ret.
}

std::vector<std::string> vec = getCoolStringVector();
[/src]

Wird der Scope an der Stelle verlagert oder so?
Oder habe ich dann in "vec" nur noch Mist drin stehen?

--- [2017-11-08 14:51 CET] Automatisch zusammengeführter Beitrag ---

Antwort auf meine eigene Frage:
Returning references can be evil!
 
Oben