Zum Inhalt springen

C++ und die verdammten pointer...


Empfohlene Beiträge

Geschrieben

Hallo an alle,

Ich bin gerade dabei einen Tieferen blick auf C++ zu werfen und prügel mich gerade mit Pointern rum. Aus irgendeinen grund tu ich mich irgendwie schwer daran sie zu verstehen und einen nutzen zu entdecken ...

Ich wollte einfach mal fragen ob ich es begriffen habe oder ob ich total daneben liege wie ich es darstelle.

Ein kleines Beispiel aus der realen Welt:

Ich sitze gerade in meinem Büro und wir gehen mal davon aus das alle meine kollegen am Tisch ein Objekt Person darstellen die auf ihren Stühlen (der adresse) sitzen. Ich bin jetzt sozusagen ein Pointer der auf Personen Zeigt.

Ich selber habe eine Adresse (Mein stuhl) und zeige auf den platz meines Arbeitskollegen zu meiner rechten vom typ Person.

in code würde das glaube ich so aussehen.


Person peter;

Person *ich = &peter;

Gehen wir nun davon aus jemand kommt und will von mir wissen worauf ich zeige dann sage ich ihm auf sitzplatz von peter. Fragt man mich aber auf was ich zeige dann zeige ich auf peter.

//zeige auf den stuhl

cout << ich << endl;

//zeige auf peter

cout << *ich << endl;

Fragt mich nun jemand wo ich sitze dann sag ich stuhl 1.

cout << &ich << endl;

Wäre jemand so nett sich den vielleicht etwas "bescheuerten" text anzuschauen und mir zu sagen ob ich das mit den Pointern richtig verstanden habe oder nicht?^^

Aber vorallem wozu brauch ich Pointer überhaupt, Java kommt ja anscheinend auch ohne aus wozu gibts dann überhaupt sowas wie Pointer :confused:

?

Vielen Dank für eure Mithilfe

Skuzzle

Geschrieben
Wäre jemand so nett sich den vielleicht etwas "bescheuerten" text anzuschauen und mir zu sagen ob ich das mit den Pointern richtig verstanden habe oder nicht?^^
In etwa. Cout ist hier für die Veranschaulichung ungeeignet, weil es mit Personen und Zeigern darauf nichts anfangen kann.

Folgende Zeilen würden dasselbe bewirken, solange du nicht auf jemand anderen zeigst:

cout << *ich << endl;
cout << peter << endl;[/code]

Aber vorallem wozu brauch ich Pointer überhaupt, Java kommt ja anscheinend auch ohne aus
In Java gibt es das auch, nur nennt man es dort Referenzen. Und da man in Java nur über solche Referenzen auf Objekte zugreifen kann, gibt in Java quasi mehr Zeiger als in C++.

Zeiger braucht man immer dann, wenn eine optionale oder veränderliche Objektbeziehung ausgedrückt werden soll, denn Zeiger können Null sein, und man kann sie auf anderen Objekte umbiegen.

Die Verwendung roher Zeiger versucht man in C++ aber sowieso eher zu vermeiden.

Geschrieben

Also das Beispiel ist schon interessant, aber ich denke im Grunde stimmt es schon. Ich finde das als Bsp etwas einleuchtender:


char c = 'a';

char* p = &c;

die erste Zeile legt eine Variable vom Typ char mit dem Inhalt "a" an. Der & Operator liefert dann von der Variablen c die Adresse zurück, da das ein Zeiger ist muss ich diese in einem char* speichern.
Aber vorallem wozu brauch ich Pointer überhaupt, Java kommt ja anscheinend auch ohne aus wozu gibts dann überhaupt sowas wie Pointer
Auch hier ein kleines Beispiel:

function ( const myobject px );

function ( const myobject& px );

Nehmen wir an, Du hast im Speicher ein Objekt erzeugt und willst dieses nun in einer Funktion verwenden. Dann würde bei der ersten Zeile eine komplette Kopie des Objektes erzeugt werden (schau Dir dazu Shallow & Deep-Copy an) und Du kannst damit dann in der Funktion arbeiten. Bei dem zweiten Aufruf wird nur ein Referenz auf das Objekt erzeugt, d.h. Du arbeitest auf dem Objekt selbst und es wird nicht kopiert.

In Java muss halt eben der Compiler entscheiden, wie er die Parameter übergibt sprich call-by-reference (&) oder call-by-value. Zeiger ermöglichen halt in vielen Fällen einen höhere Zugriffsgeschwindigkeit, weil ich eben nicht Inhalte kopieren muss, sondern eben nur Zeiger umhänge. Der Nachteil, ich muss halt wissen, was ich da mache.

Ich habe mit sehr großen Datenmengen zu tun, so dass ich mehrdimensionale Cubes darstellen will bzw. mit denen rechne. Wenn ich bei jedem Funktionsaufruf einen Shallow-Copy machen würde (Deep-Copy wäre schlimmer), würde das Programme mehrere Minuten mit dem Kopieren beschäftigt sein. Da ich iterative Algorithmen verwende hätte ich solche Aufrufe bei der Iteration, was eben nicht mehr praktikabel ist.

Ich arbeite eben mit Zeigern und Referenzen, so dass ich eben der Funktion einen Zeiger auf die Elemente gebe, die sie bearbeiten soll, was eben viel schneller ist.

Geschrieben (bearbeitet)

Das Beispiel mit den Stühlen ist soweit korrekt - wobei es mir schwerer fällt, das ganze mit Stühlen und Personen zu schildern, als den konkreten Sachverhalt zu benennen.

Vorallem nutzt man Zeiger um auf Strukturen zu verweisen, wenn es zu kostenintensiv wäre, mit den Strukturen selbst zu arbeiten.

Beispielsweise ist es sinnvoller ein Array mit Zeigern auf Kundendaten zu sortieren, als die Speicherbereiche in denen die Daten selbst liegen durch die Gegend zu schubsen. Überhaupt werden Zeiger häufig im Zusammenhang mit Speicherblöcken und Speicheroperationen verwendet.

Zeiger bieten wie gesagt die Möglichkeit zur Indirektion. Anstatt wie in den "guten alten Tagen" Daten einfach so in den Hauptspeicher zu schreiben, hat man mit Zeigern die Möglichkeit indirekt auf Speicherbereiche zuzugreifen, ohne zur Compilezeit schon zu wissen, wo genau sich dieser Speicher während der Laufzeit befindet.

Neben den eigentlichen Zeigern in C++ gibt es auch noch die Sogenannten Referenzen, die sich quasi wie Zeiger Verhalten, jedoch mit einigen gravierenden Unterschieden (e.g. können nicht NULL sein, können nicht "reseated" werden etc.).

Ein Anwendungsgebiet für Referenzen ist die Möglichkeit, Referenzen in Aufrufparametern zu benutzen.

Zeiger sind in der Tat ein mächtiges Werkzeug - allerdings zu einem recht hohen Preis: Komplexität des Verständnisses und Fehleranfälligkeit des Codes.

Eine Vielzahl an Fehlern lassen sich auf Speicherlecks, falsche Indirektionsanweisung, fehlende Initialisierung von Zeigern etc. zurückführen.

In vielen modernen Hybrid-Sprachen wie Java oder C# wird die Speicherverwaltung von der Laufzeitumgebung verwaltet. Wann also Speicher für Objekte angelegt wird, resp. wieder freigegeben wird, entscheidet die Runtime, i.e. der sog. "Garbage-Collector". Insofern entfällt an dieser Stelle die Notwendigkeit per Zeiger auf Speicherbereiche zurückzugreifen.

Desweiteren ist man den Schritt gegangen, dass man allgemein zwischen sogenannten primitives / value-types (Java/C#) und reference types unterscheidet.

Hier mal ein Beispiel in C#


int i=0; // value type

int j=1;

StringBuilder a = new StringBuilder(); //referernce types
StringBuilder b = new StringBuilder();

i=j;

b=a;
a.Append("Hello");
b.Append("World");

Console.WriteLine("i:{0} j:{1} a:{2}", i,j,a.ToString());
[/PHP]

Während [i]i[/i] und [i]j[/i] auf ihre jeweiligen Daten direkt verweisen, gibt es ein Verhältnis der Indirektion bei [i]a[/i] und [i]b[/i]. [i]a[/i] verweist lediglich auf ein Objekt vom Typ [i]StringBuilder[/i]. Und das führt zu dem unerwarteten Ergebnis, dass die Operation [i]b.Append("World")[/i] nicht einem zweiten, separaten StringBuilder das "World" anhängt, sondern [i]a[/i].

Allerdings kann man nicht sagen, dass es sich bei [i]a[/i] um einen Zeiger handelt (auch wenn innerhalb der Runtime derartiges Verhalten mit Zeigern realisiert wird).

Ebenso falsch ist es zu sagen, dass Referenztypen durch [i]call per reference[/i] übergeben werden; im Gegenteil: es erfolgt eine Übergabe der Reference [i]by vaule[/i] (c.f. StringBuilder-Beispiel). Java bspw. kennt kein [i]call by reference[/i]

Diese Unterscheidung zwischen Primitiven und Referenztypen bringt es mit sich, dass man als Programmierer von den Niederungen -und somit einer großen Quelle an Fehlern- der Zeigerarithmetik befreit worden ist. Daher benötigt man keine Zeiger mehr.

Unter C# gibt es allerdings die Möglichkeit sog. [i]unmanaged/-safe code[/i] zu schreiben, wo man auch wiederum auf C++-artige Pointer zurückgreifen kann.

Bearbeitet von lilith2k3
Geschrieben

Diese Unterscheidung zwischen Primitiven und Referenztypen bringt es mit sich, dass man als Programmierer von den Niederungen -und somit einer großen Quelle an Fehlern- der Zeigerarithmetik befreit worden ist.

Das klingt negativ. Man kann sich sicherlich darüber streiten, ob man für eine einfach Business Applikation Zeiger benötigt, aber gerade bei Sprachen wie Java wird eben argumentiert: Die Speicherverwaltung macht die VM und aufräumen mach der GC. Es gibt eine Vielzahl an Problemstellungen, wo man eben solche Datenmengen verarbeiten muss, bei der eine direkte Speicherverwaltung bzw das Arbeiten mit Zeigern oder Referenzen zu einer wesentlich höheren Performance führt.

Z.B. gleiche Algorithmik einmal unter Matlab und einmal unter C++ mit LAPack und Boost. Matlab ist Java basiert nutzt aber intern Boost und LAPack. Gerade bei mehrdimensionalen Cubes zeigt sich schon der Performancegewinn in nativen C++ Code bei ein paar 1000 Datensätzen.

Datenvolumen > 1.000.000 n-dimensionale Datenpunkte kann Matlab nicht mehr innerhalb einer Funktion handeln.

Geschrieben

Naja, was heißt negativ. Ich sage es so, wie es ist. Programmieren mit Pointern ist kein Spaß und erfordert ein Höchstmaß an Genauigkeit; und wer Probleme mit Pointern vermeiden will, sollte sich an die genannten Hochsprachen halten. Dass damit selbstredend auch Performanceverluste einhergehen, dessen sollte man sich schon bewusst sein. Allerdings sind m.E. die Verluste für einen Großteil der 08/15-Anwendungen nicht wirklich von Belang. Die Jitter tun im Hintergrund schon einen guten Job. Natürlich wird eine hochoptimierte Anwendung in C++ konkurrenzlos schnell sein ohne Frage (unter C vielleicht noch schneller als unter C++). Zu dem von Dir geschilderten Anwendungsfall kann ich nichts sagen.

Für mich als Programmierer stellt sich neben der Frage nach der Performance einer Applikation auch die Frage nach der Menge an Code, den ich schreiben muss um ein gewünschtes Ziel zu erreichen; bzw. nach der Komplexität/Fehleranfälligkeit. Und unter dem Gesichtspunkt fällt die Fehleranfälligkeit tatsächlich als Negativum auf.

Die Frage ist nicht, ob Zeiger eleganter oder schneller sind, sondern ob sie notwendig bzw. angemessen sind. Und je nach Anwendungsfall sind sie entbehrlich.

Geschrieben
Dass damit selbstredend auch Performanceverluste einhergehen, dessen sollte man sich schon bewusst sein. Allerdings sind m.E. die Verluste für einen Großteil der 08/15-Anwendungen nicht wirklich von Belang.

da stimme ich so zu

Für mich als Programmierer stellt sich neben der Frage nach der Performance einer Applikation auch die Frage nach der Menge an Code, den ich schreiben muss um ein gewünschtes Ziel zu erreichen; bzw. nach der Komplexität/Fehleranfälligkeit. Und unter dem Gesichtspunkt fällt die Fehleranfälligkeit tatsächlich als Negativum auf.

Das stimmt auch. Klar führen Pointer eben dazu, dass ich mir überlegen muss, wie ich damit richtig umgehe.

Die Frage ist nicht, ob Zeiger eleganter oder schneller sind, sondern ob sie notwendig bzw. angemessen sind. Und je nach Anwendungsfall sind sie entbehrlich.

Ich denke für eine einfach GUI oder B2B Applikation, die nur Datensätze von A nach B schiebt, sind Pointer überflüssig, aber und ich sehe in den letzten Jahren häufiger auch, dass gerade für Algorithmen, die wirklich "arbeiten" müssen, eben dann z.B. Java eingesetzt wird, mit der Begründung "ist doch so schön einfach". Threading o.ä. vernachlässigt man auch, eben mit der Begründung das macht die VM schon für mich.

Wenn ich eine HTML Seite erzeuge, dann werde ich dafür sicher kein C Programm schreiben, das auf dem Server via CGI läuft, sondern ich nehme HTML. Wenn's dynamisch sein soll, dann PHP oder Python.

Ich denke man sollte immer im Kopf haben, dass man mit Pointer extrem effizient arbeiten kann, aber eben viel Know-How in das Design stecken muss.

Geschrieben (bearbeitet)
Ich denke für eine einfach GUI oder B2B Applikation, die nur Datensätze von A nach B schiebt, sind Pointer überflüssig, aber und ich sehe in den letzten Jahren häufiger auch, dass gerade für Algorithmen, die wirklich "arbeiten" müssen, eben dann z.B. Java eingesetzt wird, mit der Begründung "ist doch so schön einfach"

Man sollte wie gesagt nicht ausser acht lassen, dass eben die "modernen" Hochsprachen von der Performance immer attraktiver werden und die Notwendigkeit, auf low level-Sprachen zurückzugreifen für ein Gros der Programmierer entfällt.

Vorallem, wenn es weiter Fortschritte in der Erforschung und Entwicklung bezüglich LLVM-Einsatz bei den Compilern geben wird. Leider liegt das Unladen Swallow-Projekt derzeit quasi auf Eis; aber ich verspreche mir viel von der Entwickung.

Allerdings gebe ich Dir Recht in der Anspielung "Java ist doch schön Einfach" und den notorischen Geschwindigkeitsproblemen unter denen Java immer noch zu leiden hat.

Die Anwendungsgebiete für Sprachen wie C, C++ ("Zeiger" sind quasi pars pro toto zu verstehen *g*)werden in Zukunft weiter abnehmen. Allerdings, und das sollte man nicht vergessen, müssen ja auch die Frameworks, die Runtimes etc. in Sprachen geschrieben werden: und da eignen sich momentan die o.g. Sprachen bisher noch am besten - obwohl es mit PyPy auch schon den Versuch gibt, beispielsweise einen Python-Interpreter in Python selbst zu schreiben.

Langfristig, so denke ich, wird es darauf hinauslaufen, dass C/C++ die Sprachen sind die nur noch da relevant sind, wo sie tatsächlich ihre Stärken haben: in der maschinennahen Programmierung (nirgends sonst kann man mal eben so inline assembler einschieben *g*).

Btw. ist laut Tiobe-index Python zur Sprache des Jahres 2010 (highest rise) gekürt worden und schon seit etwas mehr als vier Jahren liegt Java an der Spitze vor C. Nicht dass ich per se an die Aussagekraft dieses Indexes glaube, aber ich denke dennoch, dass der Trend offensichtlich ist.

P.S.:

Thread-Titel einmal anders ...

»C++ und die Pointer der Verdammten« ... könnte auch ein Horror-Movie oder Italo-Western aus den 70ern sein :D

*SCNR*

Bearbeitet von lilith2k3

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...