(Cpp) Verständnisproblem: Nutzen des new-operators? (mit Beispiel)
Hallo liebe community!
INTRO:
Zunächsteinmal: Trotz mehrerer Stunden Recherche habe ich für meine Frage leider noch keine Antwort gefunden und wende mich daher vertrauensvoll an dieses Forum. Ich war früher schon mal einige Zeit hier unterwegs, habe mich aber damals mit Batch beschäftigt =) Das Forum blieb mir immer in seeehr guter Erinnerung.
Aufgrund meiner in absehbarer Zeit anstehenden Bachelorarbeit im Maschinenbau-Studium, bei der ich ein Programm in C++ schreiben kann/muss/darf/soll (=D), beschäftige ich mich nun seit einigen Tagen relativ intensiv mit C++, mit welcher ich vorher noch nie Kontakt hatte.
Mittlerweile bin ich bei "Dynamischen Strukturen - Anlegen und Freigeben von Speicher" angekommen (aus der von meinem Prof. vorgeschlagenen online-version des Buches "Einstieg in C++" von Willemer ; ich nutze auch andere Quellen wie youtube, google und die cpp-Einführung auf highscore.de, die aber keinen http-link hat, daher möchte ich sie nicht verlinken)
FRAGE:
Mir erschließt sich die Nutzung des new-operators nicht. Warum nutzt man ihn? Welche Vor- oder Nachteile hat er im Vergleich zu anderen Möglichkeiten? Ich komm nicht drauf.
BEISPIEL:
in einem youtube-guide (link) fand ich ein schönes Beispiel, bei dem mein "Problem" hoffentlich klar wird. Das Programm erzeugt eine Matrix (als Vergleich wurde ein Bild genannt), welche dann mit 0-ern gefüllt wird. Als Anzahl für Zeilen (r) und Spalten (c) übernahm ich r=800 und c=600 aus dem video. Beide Varianten funktionieren meines Erachtens einwandfrei. Daher ist mir der Vorteil der ersten nicht ersichtlich.
Beide codes (der auskommentierte original-code sowie mein eigener Versuch) Haben das gleiche Ergebnis.
Daher stellt sich mir die Frage, wozu man den new-operator braucht. Offensichtlich (für mich) kann man auch ohne new-operator während des laufenden Programms Variablen/Matrizen und so deklarieren, die dann auf Nutzereingaben (oder vermutlich auch anderen Input) reagieren und sich so dem Bedarf anpassen.
SCHLUSS
Ich hoffe, dass mein Problem ersichtlich wurde und mir jemand helfen kann =)
Sollte ich irgendetwas vergessen haben, möchte ich mich im Voraus dafür entschuldigen und werde es natürlich baldmöglichst korrigieren. Verzeigt bitte auch, sollte ich manche Begriffe falsch benutzt haben, auf die paar Tage kenne ich natürlich vieles noch nicht und bin mit der Verwendung der Fachbegriffe uU. noch nicht ganz vertraut ;) Sollten mehr Kommentare im Code erwünscht sein, ergänze ich sie gerne.
Vielen Dank schon mal an alle Kommentatoren
SinixND
INTRO:
Zunächsteinmal: Trotz mehrerer Stunden Recherche habe ich für meine Frage leider noch keine Antwort gefunden und wende mich daher vertrauensvoll an dieses Forum. Ich war früher schon mal einige Zeit hier unterwegs, habe mich aber damals mit Batch beschäftigt =) Das Forum blieb mir immer in seeehr guter Erinnerung.
Aufgrund meiner in absehbarer Zeit anstehenden Bachelorarbeit im Maschinenbau-Studium, bei der ich ein Programm in C++ schreiben kann/muss/darf/soll (=D), beschäftige ich mich nun seit einigen Tagen relativ intensiv mit C++, mit welcher ich vorher noch nie Kontakt hatte.
Mittlerweile bin ich bei "Dynamischen Strukturen - Anlegen und Freigeben von Speicher" angekommen (aus der von meinem Prof. vorgeschlagenen online-version des Buches "Einstieg in C++" von Willemer ; ich nutze auch andere Quellen wie youtube, google und die cpp-Einführung auf highscore.de, die aber keinen http-link hat, daher möchte ich sie nicht verlinken)
FRAGE:
Mir erschließt sich die Nutzung des new-operators nicht. Warum nutzt man ihn? Welche Vor- oder Nachteile hat er im Vergleich zu anderen Möglichkeiten? Ich komm nicht drauf.
BEISPIEL:
in einem youtube-guide (link) fand ich ein schönes Beispiel, bei dem mein "Problem" hoffentlich klar wird. Das Programm erzeugt eine Matrix (als Vergleich wurde ein Bild genannt), welche dann mit 0-ern gefüllt wird. Als Anzahl für Zeilen (r) und Spalten (c) übernahm ich r=800 und c=600 aus dem video. Beide Varianten funktionieren meines Erachtens einwandfrei. Daher ist mir der Vorteil der ersten nicht ersichtlich.
#include <iostream>
#include <iomanip>
using namespace std;
int main()
/*
{
int r, c;
cout << "Zeilen eingeben: " << endl;
cin >> r;
cout << "Spalten eingeben: " << endl;
cin >> c;
int **matrix = new int*[r];
for (int i=0; i<r; i++)
{
matrix[i] = new int[c];
}
for (int i=0; i<r; i++)
{
for (int j=0; j<c; j++)
{
matrix[i][j] = 0;
}
}
cout << matrix << endl;
for (int i=0; i<r; i++)
{
delete matrix[i];
}
delete matrix;
return 0;
}
*/
//An dieser Stelle endet der Code im Video. Ab hier beginnt mein eigener Versuch.
{
int r, c;
cout << "Zeilen eingeben: " << endl;
cin >> r;
cout << "Spalten eingeben: " << endl;
cin >> c;
int matrix[r][c];
for (int i=0; i<r; i++)
{
for (int j=0; j<c; j++)
{
matrix[i][j] = 0;
}
}
cout << matrix << endl;
}
Beide codes (der auskommentierte original-code sowie mein eigener Versuch) Haben das gleiche Ergebnis.
Daher stellt sich mir die Frage, wozu man den new-operator braucht. Offensichtlich (für mich) kann man auch ohne new-operator während des laufenden Programms Variablen/Matrizen und so deklarieren, die dann auf Nutzereingaben (oder vermutlich auch anderen Input) reagieren und sich so dem Bedarf anpassen.
SCHLUSS
Ich hoffe, dass mein Problem ersichtlich wurde und mir jemand helfen kann =)
Sollte ich irgendetwas vergessen haben, möchte ich mich im Voraus dafür entschuldigen und werde es natürlich baldmöglichst korrigieren. Verzeigt bitte auch, sollte ich manche Begriffe falsch benutzt haben, auf die paar Tage kenne ich natürlich vieles noch nicht und bin mit der Verwendung der Fachbegriffe uU. noch nicht ganz vertraut ;) Sollten mehr Kommentare im Code erwünscht sein, ergänze ich sie gerne.
Vielen Dank schon mal an alle Kommentatoren
SinixND
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 616395
Url: https://administrator.de/forum/cpp-verstaendnisproblem-nutzen-des-new-operators-mit-beispiel-616395.html
Ausgedruckt am: 21.12.2024 um 16:12 Uhr
20 Kommentare
Neuester Kommentar
Hi,
Wenn du vor dem Bachelor stehst, solltest du ja schon einige Berührungspunkte haben mit C++. Vorausgesetzt du hast da nicht gefehlt
Der New() -Operator erzeugt in fast allen Programmiersprachen eine neu Instanz des angegebenen Objekts
Powershell:
$a = New-Object ...
C#:
Object x = New Directoryinfo()....
Dito in cpp usw.
Hier die Referenz zu den Keywords:
https://en.cppreference.com/w/cpp/keyword
Grüße!
Wenn du vor dem Bachelor stehst, solltest du ja schon einige Berührungspunkte haben mit C++. Vorausgesetzt du hast da nicht gefehlt
Der New() -Operator erzeugt in fast allen Programmiersprachen eine neu Instanz des angegebenen Objekts
Powershell:
$a = New-Object ...
C#:
Object x = New Directoryinfo()....
Dito in cpp usw.
Hier die Referenz zu den Keywords:
https://en.cppreference.com/w/cpp/keyword
Grüße!
Moin zusammen,
kurz und simpel ausgedrückt:
Das erste Beispiel erzeugt und verwendet ein Objekt (naja, eigentlich eine Liste von Objekten)
im dynamisch "allgemeinen Speicher". Der Operateor delete gibt diesen Speicher wieder frei.
Das Objekt kann duch Dein Programm und seine Funktionen durchgereicht werden und darf nur von
Deinem Programm zerstört werden zu einem Zeitpunkt, den Du kontrollierenkannst.
Dein Beispiel erzeugt ein lokales Speicherobjekt, das nur Gültigkeit besitzt
innerhal Deiner lokalen Funktion, es wird automatisch beim Verlassen der Funktion zerstört
und kann nicht (zumindest nicht "nach oben" zurück) weitergegeben werden.
ICh hoffe, ich konnte rüberbringen, was ich meine....
Mfg
KLinnebank
kurz und simpel ausgedrückt:
Das erste Beispiel erzeugt und verwendet ein Objekt (naja, eigentlich eine Liste von Objekten)
im dynamisch "allgemeinen Speicher". Der Operateor delete gibt diesen Speicher wieder frei.
Das Objekt kann duch Dein Programm und seine Funktionen durchgereicht werden und darf nur von
Deinem Programm zerstört werden zu einem Zeitpunkt, den Du kontrollierenkannst.
Dein Beispiel erzeugt ein lokales Speicherobjekt, das nur Gültigkeit besitzt
innerhal Deiner lokalen Funktion, es wird automatisch beim Verlassen der Funktion zerstört
und kann nicht (zumindest nicht "nach oben" zurück) weitergegeben werden.
ICh hoffe, ich konnte rüberbringen, was ich meine....
Mfg
KLinnebank
Wenn du new in C++ nutzt, hast du im Zweifelsfall einen Designfehler in deinem Programm. Wenn du new ohne Verwendung eines Smartpointers verwendest, hast du definitiv etwas falsch gemacht. Die Gefahr eine Speicherverletzung zu verursachen ist zu groß, darum baut C++ auf das RAII Prinzip. In deinem Fall würde man eine der STL Containerklassen nutzen. Youtube ist in aller Regel kein guter Anlaufpunkt um Programmieren zu lernen...
Steffen
Steffen
Gut, was new macht ist glaube ich hinreichend erklärt. Es stellt dir Speicher vom Stack zur Verfügung, der dann durch delete wieder freigegeben muss. Bei Smartpointern erledigt letzteres der Destruktor.
Anmerkung noch zu deinem eigenen Code - du erzeugst ein sogenanntes Variable Length Array (VLA). Das wird auf dem Heap allokiert. Geht ganz schnell ohne jede Vorwarnung in die Hose wenn du zu viele Elemente allokieren musst und solltest du unter allen Umständen vermeiden!
Steffen
Anmerkung noch zu deinem eigenen Code - du erzeugst ein sogenanntes Variable Length Array (VLA). Das wird auf dem Heap allokiert. Geht ganz schnell ohne jede Vorwarnung in die Hose wenn du zu viele Elemente allokieren musst und solltest du unter allen Umständen vermeiden!
Steffen
- new ist "persistent" bis "delete", die variable gilt also auch außerhalb (über/unter?) der klammer
Hmpf. Der Pointer (die Adresse des allokierten Speichers) bleibt gültig. Variablen selber haben aber immer eine definierte Sichtbarkeit (Scope). Du kannst also nicht einfach eine Variable foo in der main deklarieren und ihr einen allokierten Pointer zuweisen, und anschließend davon ausgehen dass du die Variable foo in einer anderen Funktion verwenden kannst. Du kannst einen allokierten Pointer aber aus einer Funktion zurückgeben, ohne Gefahr zu laufen dass er ungültig wird.- new weist der erstellten variable/array auch gleich einen Zeiger zu, was sonst in zwei schritten gemacht werden müsste
Was meinst du mit "sonst"? Du allokierst so etwas wie ein zweidimensionales Array. Dazu wird ein Array von Pointers auf int allokiert, der die "Zeilen" als Elemente beinhalten. Für jede Zeile muss aber noch mal ein Array von int allokiert werden für die Einzelwerte einer Zeile. Jeder dieser Pointerwerte muss mit delete wieder freigegeben werden. Da reden wir also von wesentlich mehr als nur zwei Schritten.- new erlaubt (noch nicht im skript definierte) variablen in arrays (entspricht definition zu laufzeit?). dies geht bei einer "normalen" array-deklaration nicht (entspricht definition zu kompilier-zeit?)
Richtig. Wenn die Größe erst zur Laufzeit festgelegt wird, baust du ansonsten ein VLA.Aber ich muss noch mal klar darauf hinweisen, dass das kein gutes C++ wird. Die STL bietet dir hier std::array oder std::vector für solche Zwecke …
Steffen
zu 1) dh, obwohl die Variable außerhalb des scopes nicht mehr ansprechbar ist, bleibt der zugewiesene pointer ansprechbar?
Er bleibt gültig. Aber ohne Variable (die nichts anderes tut als den Pointer/die Adresse zu speichern) hast du keinen Zugriff. Und genau da liegt die Gefahr. Verlierst du die Adresse (indem eine Variable überschrieben oder ungültig wird, oder indem der ursprüngliche Pointerwert durch Pointerarithmetik verändert wurde), dann kann er nicht mehr freigegeben werden und du erzeugst ein Speicherleck.2) mit "sonst" meinte ich, dass man sonst (1.) bspw. ein array deklarieren muss, auf welches man dann (2.) einen pointer referenziert.
ich wüsste beispielsweise gar nicht, wie ich "nachträglich" pointer auf die elemente eines "int array[5][5]" referenzieren > könnte. falls das mit for-schleifen klappt, ist in der hinsicht der new-operator "nur" kürzer zu schreiben.
Ein Array ist immer gleichzeitig ein Pointer. Im Gegensatz zu einer Arrayvariablen enthält aber eine Pointervariable keinen Hinweis mehr, auf wie viele Elemente verwiesen wir. Man spricht von Array-To-Pointer-Decay.ich wüsste beispielsweise gar nicht, wie ich "nachträglich" pointer auf die elemente eines "int array[5][5]" referenzieren > könnte. falls das mit for-schleifen klappt, ist in der hinsicht der new-operator "nur" kürzer zu schreiben.
Ich hatte da vor einiger Zeit mal was dazu runtergeschrieben …
https://dev-community.de/resources/c-pointer.6/
Steffen
Darüber scheiden sich die Geister. Erstmal
ist dasselbe wie
ist dasselbe wie
In Punkto intuitiv kannst du auf die Nase fallen. Beispiel:
Wenn du jetzt denkst, dass x auch ein Pointer ist, liegst du verkehrt, denn x ist ein int. Darum ziehe ich das Asterisk vor den Variablenname:
Nun ist klar, auch x ist ein Pointer Aber wie gesagt, das ist lediglich eine Frage des Stils, den du für dich selbst finden musst, dann aber möglichst konsistent verwenden solltest um den Leser des Codes nicht zu verwirren.
Steffen
int *p;
ist dasselbe wie
int * p;
ist dasselbe wie
int* p;
In Punkto intuitiv kannst du auf die Nase fallen. Beispiel:
int* p, x;
Wenn du jetzt denkst, dass x auch ein Pointer ist, liegst du verkehrt, denn x ist ein int. Darum ziehe ich das Asterisk vor den Variablenname:
int *p, *x;
Nun ist klar, auch x ist ein Pointer Aber wie gesagt, das ist lediglich eine Frage des Stils, den du für dich selbst finden musst, dann aber möglichst konsistent verwenden solltest um den Leser des Codes nicht zu verwirren.
Steffen
Zitat von @SinixND:
auch eine Variablen-deklaration erzeugt doch eine neue Instanz, oder? wo ist also der mehrwert ggü. der (viel kürzeren) Variante?
auch eine Variablen-deklaration erzeugt doch eine neue Instanz, oder? wo ist also der mehrwert ggü. der (viel kürzeren) Variante?
Wenn du eine Variable deklarierst, dann erstellst du ein neues Object der BASE (z.B. String), das stimmt. der New-Operator erstellt aber eine neue Instalnz des Objects das du schon erstellt hast.
bsp:
class MeineKlasse
{
...
}
var nw = new MeineKlasse();
Grüße!
Zitat von @SinixND:
>
> int main()
> {
> {
> int *p = new int(1);
> cout << *p << endl;
> delete p;
> }
> //cout << *p << endl;
>
> }
>
Ich weiß inzwischen, dass der new-Befehl sehr unbeliebt ist, weil man viele Fehler machen kann und es wohl sowohl dafür als auch für Pointer bessere Lösungen gibt. Ich Frage nur um des Wissens willen =)
Ist schon einige Zeit her, da ich mich mit cpp gespielt habe, aber wenn sich nichts geändert hat dann ist das Problem immer noch der Carbagecollector. Der Destruktor der BASE wird nicht automatisch aufgerufen und dein Objekt existiert bis zum Nimmerleinstag. Ergo: irgendwann gibts einen Stackoverflow.
In C# passiert das automatisch. Und da ist der New-Operator bei einigen Dingen ein muss weil Instanzen nur so vererbt werden können. Da gibts allerdings auch keine Pointer, alloc usw. Alles automatisiert.
Grüße!
Zitat von @rubberman:
Steffen
Carbagecollector
In C++? Nee, da gibt's so etwas nicht. C# unterscheidet sich da grundlegend. Auch hinsichtlich new, das man in C++ nur in Ausnahmefällen verwendet und, wie schon geschrieben, ohne Smart Pointer Klasse baut man mit new gleich mal grundsätzlich einen Designfehler in den Code.Steffen
Wusste ich doch dass es einen Grund hatte warum ich mit cpp aufgehört habe