Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

11

09.10.2014, 12:40

Also nach längeren Überlegungen,Recherchen und zuguterletzt eurer Hilfe meine ich jetzt das Prinzip um den Heap und den Stack verstanden zu haben.
Es gibt jedoch einen Satz im Buch, den ich ncht so recht einordnen kann.

Und zwar handelt es sich dabei um den letzten Satz.

Zitat

Fangen wir mit einem kleinen Rückblick zum Thema Stack und Heap an. Es wurde ja
geklärt, dass lokale Variablen auf dem Stack erzeugt werden. Diese werden gelöscht, nachdem
der Gültigkeitsbereich, in dem sie erzeugt wurden, verlassen wird. Das hat den Nachteil,
dass wir zum Beispiel Probleme bekommen, wenn wir innerhalb einer Funktion eine
Instanz einer Klasse erzeugen, die aber nach Verlassen der Funktion weiterhin gültig sein
soll. Globale Variablen kommen als Ausweg nicht infrage, also bleibt nur noch die Möglichkeit,
die Klasseninstanz über den Rückgabewert an die aufrufende Funktion zu übergeben.
Das ist allerdings recht zeitraubend, da wieder eine komplette Kopie der Instanz auf dem
Stack abgelegt werden muss. Erschwerend kommt hinzu, dass man ja nur einen einzigen
Rückgabewert zur Verfügung hat.


Beim Beispiel vom Architekten z.b.


int
* test()
{
int *x= new int;

return x;
}



Wie auch beim Beispiel von Roflo


#include <iostream>
using namespace std;

int *test1()
{
int i = 446688;
return &i;
}

void test2()
{
int z = 995577;
}

int main()
{
int *t = test1();
test2();

cout << *t;
cin.get();
}

werden jeweils diese Rückgabewerte verwendet.

Worauf ich hinaus will ist, inwiefern müssen wir aufgrund der Erzeugung auf dem Heap nicht mehr mit(einzelnen)Rückgabewerten arbeiten?


In euren Beispielen macht ihr dies ja, Herr Kalista gibt das aber scheinbar als Nachteil der Stackerzeugung an in dieser Textpassage.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »n00bman« (09.10.2014, 17:00)


12

09.10.2014, 14:38

Herr Kalista meint, du kannst mehr als nur einen wert zurück liefern, wobei das ganze nicht wirklich stimmt.
Eine Funktion kann nur einen Wert zurück liefern.


Was Herr Kalista meint, du übergibst der Funktion als Parameter einen Pointer

Hier als Beispiel:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int Test( int* p);
int main()
{

int *MeineIntVariable=new int;    //Eine erzeugte int Variable die mit New angelegt wurde auf dem Heap

MeineIntVariable=10;

//Noch eine Zweite Variable:
int Rueckgabevariable;  //Normale Int Variable die Nacher den Wert der Rückgabe besitzt

Rueckgabevariable=20;

//Jetzt der Funktionsaufruf, um beide Variablen zu verändern(den Wert)

Rueckgabevariable=Test(MeineIntVariable);

return 0;
}
int Test( int* p)
{
  p=20;

return 20;
}



So und nun die erklärung:

Ein >Pointer zeigt auf eine Variablenadresse, hier ist es die Adresse die von new Zurückgeliefert wird. Es entspricht der schreibweise:

int* Pointer=NULL;
int Testvariable=20;

Pointer=&Testvariable;

Bei dem Beispiel ist aber zu sagen, das Testvariable auf dem Stack erzeugt wurde, sie ist nur im momentanen Block oder Funktion erreichbar und wird zerstört sobald der Block oder die Funktion verlassen wird.

In der Funktion wird MeineIntVariable nicht als wert übergeben also die 10 sondern die Adresse des Speichers wird übergeben.
Das Heißt in der Funktion wird auf diese Adresse zugegriffen und geschrieben, wie du dir jetzt sicherlich denken kannst, ist die Adresse sowohl in der Funktion als auch in main immernoch verfügbar und das so lange bis du diesen Speicher mit delete wieder frei gibst.



Somit kannst du zwei Variablen in einer Funktion verändern, dies geht mich unendlich vielen Parametern!

Hoffe ich konnte helfen


Gruß Leri

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »leridan« (09.10.2014, 14:44)


buggypixels

Treue Seele

Beiträge: 125

Wohnort: Meerbusch

Beruf: Programmierer

  • Private Nachricht senden

13

09.10.2014, 15:56

Das Beispiel ist natürlich fehlerhaft!
Also wenn man

C-/C++-Quelltext

1
int* MeineIntVariable = new int

macht und dann den Wert setzen will ist das natürlich

C-/C++-Quelltext

1
*MeineIntVariable = 20;

Ansonsten würde man den Wert des Zeigers ändern! Besser da aber nicht dran rumfummeln.
Es muß übrigens nicht zwangsläufig ein Pointer sein, sondern eine Referenz geht auch.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct Test {
 int value;
};

void changeTest1(Test& t) {
  t.value = 100;
}
void changeTest2(Test* t) {
  t->value = 200;
}
int main() {
  Test t1;
  changeTest1(t1);
  Test t2;
  chnageTest2(&t2);
  cout << "T1 " << t1.value;
  cout << "T2 " << t2.value;
}

Grundsätzlich geht es aber um die Frage des Lebenszyklus einer Variable. Die Erklärung von Herrn Kalista ist da etwas eigenwillig.
Am dem Beispiel mit einem "int" ist das auch eher doof zu erklären.
Nehmen wir mal etwas komplexeres

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct Values {
  int iv;
  float fv;
}

Values buildValue(int v,float u) {
  Values v;
  v.iv = v;
  v.fv = u;
  return v;
}
int main() {
  Values test = buildValue(200,300.0f);
}

Was passiert hier genau. Der Scope von der Variable "v" in der Methode buildValue gilt nur innerhalb der Methode. Warum geht es aber über den Rückgabewert?
Weil intern der Compiler eine Kopie der Variable test erstellt und die Werte von v dort hinein kopiert. Somit hat "v" zwar seinen Scope verloren und existiert nicht mehr
aber die Werte selber sind kopiert worden.
Einfaches Beispiel:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
class Values {

public:
  Values() : iv(0) , fv(0.0f) {}
private:
  int iv;
  float fv;
  Values(const Values& org) {}
}

Damit geht es dann nicht, weil der Copy Konstruktur private ist.
Lange Rede, wenn Du das so machen willst, also lokale Variable erstellen als Rückgabewert, dann denk daran, dass die Werte kopiert werden.

14

09.10.2014, 17:26

Oki doke! Vielen Dank! Jetzt kann ich das Ganze schon ein bisschen besser zuordnen. Das Buch ist echt top, aber die Erzeugung einer Klasse auf dem Heap wird dort scheinbar zu stark gehyped^^
Den Formulierungen nach zu urteilen klang das so, als würde man durch eine Erzeugung auf dem Heap quasi eine globale Variable/Klasse ohne Nachteile erzeugen :D

15

09.10.2014, 17:51

An dieser Stelle noch eine letzte Frage von mir :D danach zerbrech ich mir den Kopf selbst auch wenns Stunden dauert ^^
Was meint Herr Kalista hiermit?

Zitat

Wenn wir eine Instanz des Logfiles erzeugen, so müssen wir diese
Instanz in jeder .cpp-Datei, in der wir sie verwenden wollen, natürlich auch irgendwie
bereitstellen. Dazu haben wir bisher zwei Möglichkeiten: Entweder übergeben wir einen
Zeiger auf die Logfile-Instanz von Klasse zu Klasse
, oder wir verwenden das Schlüsselwort
extern. Die erste Lösung schreit förmlich nach Overkill und viel zu viel unnötiger Arbeit.
Was soll das sein? Ich hab das Buch bis zu der Stelle zig mal durchgeblättert und kann mir beim besten Willen nichts darunter vorstellen. :hmm:

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

16

09.10.2014, 18:14

Vergiss das ganz schnell. Die Wurzel allen Übels ist Faulheit. Sei es als Singleton, globaler Variable (extern) oder ähnlichem Mist. Ein Log ist da keine Ausnahme und sollte pro Klasse dann lieber per Factory erzeugt werden können. Er hat allerdings Recht, dass ein Log zu übergeben großer Quatsch ist, weil ein Log wirklich in jeder einzelnen Methode mal gebraucht werden kann. Daher will er es nicht als Parameter übergeben. Sonst hätte jede Methode mindestens das Log als Parameter und das erzeugt nur hässlichen Ballast, der die Lesbarkeit erschwert (auch "Noise" genannt).

Es als Pointer zu übergeben wäre zudem auch eine Unschönheit, die Herr Kalista da nicht so gut verwendet. Eine Referenz wäre korrekt, da muss nämlich etwas gültiges übergeben werden. Bei Pointern muss man das ja nicht.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

17

09.10.2014, 19:02

ja aber was meint er mit dem unten geizeigten Punkt von dem er abrät? Wie sähe so eine Operation aus?

Zitat


[u]Entweder übergeben wir einen

Zeiger auf die Logfile-Instanz von Klasse zu Klasse
[/u]

18

09.10.2014, 19:09

Du übergibst dem Konstruktor einer Klasse eben eine Referenz auf die LogKlasse. Wenn diese wieder Instanzen von anderen Klassen erzeugt, übergibt diese wiederum eine an dessen Konstruktor. Und so weiter.

Werbeanzeige