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

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

11

13.10.2010, 12:11

Das Richtige für seinen Fall wäre es keine Globale Variable zu verwenden...

BurningWave

Alter Hase

Beiträge: 1 106

Wohnort: Filderstadt/Konstanz

Beruf: Student

  • Private Nachricht senden

12

13.10.2010, 12:51

Das Richtige für seinen Fall wäre es keine Globale Variable zu verwenden...

Genau das meine ich auch.

@BurningWave: Ohne sie vorher einmal global zu initialisieren beschwert sich mein compiler (gcc), wenn ich sie im ctor initialisiere. Außerdem will ich sie ja nicht in jedem c'tor initialisieren, sondern nur 1 mal, und die klasse ist nunmal kein singleton

Und was spricht gegen sowas in der Art, wenn die Variable schon statisch sein muss:

C-/C++-Quelltext

1
2
3
4
5
6
7
CClass::CClass()
{
     if(!m_pStaticVar)
          // m_pStaticVar initialisieren

     // [...]
}

TGGC

1x Rätselkönig

Beiträge: 1 799

Beruf: Software Entwickler

  • Private Nachricht senden

13

13.10.2010, 13:01

Der Link war sehr hilfreich, danke, aber er widerspricht (teilweise) dem was du sagst ^^ In meinem Eröffnungspost hatte ich ja von mehreren .cpp dateien gesprochen.

Zitat: "Für zwei globale Variablen aus unterschiedlichen Übersetzungseinheiten ist die Reihenfolge dagegen nicht vorgeschrieben. Daher sollte man nie eine von ihnen mit dem Wert der anderen initialisieren; das Ergebnis kann von Compiler zu Compiler verschieden sein"

Das war genau das, was ich wissen wollte :)
Naja, es ist festgelegt, denn "so wie der Compiler mag" ist auch eine Festlegung. Die eigentlichen Vokabeln um sowas zu beschreiben sind aber "undefined" und "unspecified", denn dazu wird im Standard genau beschrieben, was das heisst.

n0_0ne

1x Contest-Sieger

  • »n0_0ne« ist der Autor dieses Themas
  • Private Nachricht senden

14

14.10.2010, 09:21

@TGGC: ok, du hast nix falsches gesagt ;)

@BurningWave: auch in dem fall müsste ich die variable vorher einmal global initialisieren, sonst gibts wie gesagt, nen compilererror ^^ außerdem seh ich da nicht so wirklich den vorteil?

@FalkT: ich verstehe nicht wirklich, was du meinst, könntest du es nochmal erklären? ^^

Vielleicht ein paar mehr Infos zu meinem Szenario:
Ich habe eine abstrakte (hat pure virtual methoden) Klasse RenderObject mit einigen Hilfsfunktionen und einige Klassen, wie z.B. Cube, Sphere, die von RenderObject erben. Vorher hatte ich die ganzen Daten, wie ein Cube aussieht z.B. in jedem Cube extra gespeichert (sehr viel redundanz). Jetzt will ich es so machen, dass pro Klasse diese daten immer nur 1 mal verfügbar sind, und sie von den hilfsfunktionen von RenderObject genutzt werden können. Mein Vorgehen bis jetzt:
RenderObject eine virtuelle methode getVar() verpasst;virtual, damit immer die passende methode der Kindklasse aufgerufen wird. Diese wird in den Kindklassen implementiert und liefert dann immer die statische variable der Klasse zurück. Diese wird (wie in meinem anfangspost) ein mal mit einer statischen methode initialisiert.

Warum ist dieses vorgehen denn so schlecht? und wie würdet ihr es machen?

FalkT

Treue Seele

Beiträge: 125

Wohnort: AC

  • Private Nachricht senden

15

14.10.2010, 11:55

@FalkT: ich verstehe nicht wirklich, was du meinst, könntest du es nochmal erklären? ^^
Ein Singleton regelt den Zugriff auf ein Objekt und dessen Erzeugung.
Normalerweise wird für die Erzeugung der Default-Constructor verwendet.

Ich beziehe mich immer auf die Ausführungen von Alexandrescu in seinem Buch "Modern C++ Design".
Siehe beispielsweise mal Hier .

Die Umsetzung ist dann wie folgt:

C-/C++-Quelltext

1
2
3
4
class MyClass
{
  static MyClass* instance() { return Singleton<MyClass>::instance(); }
}


Wenn man mehr Magie bei der Erzeugung möchte, dann entsprechend:

C-/C++-Quelltext

1
2
3
4
class MyClass
{
  static MyClass* instance() { return Singleton<MyClass, MySpecialConstructionPolicy>::instance(); }
}


Aber die instance-Function muss nicht zwangsweise an die Klasse gebunden sein und die Zugriffs-Funktion muss nicht zwangsläufig static sein.

C-/C++-Quelltext

1
2
3
4
5
class GlobalData
{
 MyClass* MyClass_instance() { return Singleton<MyClass>::instance(); }
 MyClass2* MyClass2_instance() { return Singleton<MyClass2>::instance(); }
}


Ich persönlich finde aber nichts dümmer als von dieser Singleton-Klasse ableiten zu müssen.
Das verfälscht meistens den Zweck von dem was man wirklich tun möchte.

C-/C++-Quelltext

1
class MyClass : public Singleton<MyClass> 

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

16

14.10.2010, 12:02

Vielleicht ein paar mehr Infos zu meinem Szenario:
Ich habe eine abstrakte (hat pure virtual methoden) Klasse RenderObject mit einigen Hilfsfunktionen und einige Klassen, wie z.B. Cube, Sphere, die von RenderObject erben. Vorher hatte ich die ganzen Daten, wie ein Cube aussieht z.B. in jedem Cube extra gespeichert (sehr viel redundanz). Jetzt will ich es so machen, dass pro Klasse diese daten immer nur 1 mal verfügbar sind, und sie von den hilfsfunktionen von RenderObject genutzt werden können. Mein Vorgehen bis jetzt:
RenderObject eine virtuelle methode getVar() verpasst;virtual, damit immer die passende methode der Kindklasse aufgerufen wird. Diese wird in den Kindklassen implementiert und liefert dann immer die statische variable der Klasse zurück. Diese wird (wie in meinem anfangspost) ein mal mit einer statischen methode initialisiert.

Warum ist dieses vorgehen denn so schlecht? und wie würdet ihr es machen?

Wie klingt folgender Vorschlag für dich:

Du hast eine Klasse Cube die intern die Daten wie ein Cube aussieht etc. hält. Diese Klasse hat eine Methode CreateInstance() der du z.B. die Abmessungen deines Würfels übergibst und die dir ein entsprechendes RenderObjekt* zurückgibt. Problem gelöst, ganz ohne globale oder statische Variablen oder Singletons...

n0_0ne

1x Contest-Sieger

  • »n0_0ne« ist der Autor dieses Themas
  • Private Nachricht senden

17

14.10.2010, 15:24

@FalkT: danke für die Erläuterungen, ich hab bis jetzt immer von Singleton geerbt, auf die anderen Möglichkeiten wäre ich nie gekommen ^^

@dot: so wie ich dich verstanden habe, hat am ende dann aber doch jedes renderobject die topologischen daten gespeichert?

@all: was ist denn eigentlich an den (globalen) statischen variablen soooo schlimm? ^^
Ich hab es jetzt etwas umgeschrieben:
die statische variable ist jetzt nicht mehr public, sondern private, also nicht mehr global zugängig. ich initialisiere sie am anfang jetzt einfach global mit NULL und danach nach BurningWaves vorschlag mit einem if(!staticVar) im constructor auf den richtigen wert... seid ihr damit eher einverstanden? ^^

Sylence

Community-Fossil

Beiträge: 1 663

Beruf: Softwareentwickler

  • Private Nachricht senden

18

14.10.2010, 15:52

Wenn man es richtig macht ist an globalen Variablen nichts schlimm.
Das Problem ist nur das "richtig machen". Wenn man es eben nicht richtig macht landet man schneller in unwartbarem Code als man es je für möglich gehalten hätte ;)

Jetzt dürft ihr mich gern dafür steinigen, dass ich nicht auf dem Zug "globale variablen sind immer schlimm" mitfahre...

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

19

14.10.2010, 16:43

Globale Variablen sind nicht von Haus aus böse. Genausowenig wie Singletons von Haus aus böse sind. Das Problem ist dass 99.99% aller globalen Variablen nicht da sind weil es sich um Dinge handelt die global sein sollten und dass 99.9999% aller Singletons nicht da sind weil es sich um Klassen handelt von denen es immer nur genau eine Instanz geben darf. 99.99% aller globalen Variablen und 99.9999% aller Singletons sind da weil die Programmierer zu faul waren es richtig zu machen und/oder die zugrundeliegenden Konzepte nicht oder falsch verstanden haben. Der Grund für praktisch alle Singletons und globalen Variablen heute ist: "Weil ich von überall aus drauf Zugriff haben will". Und das ist genau das falsche Argument (man beachte wie das Wort "will" plötzlich zu einem "muss" wird sowie dass der globale Zugriff nur ein Nebeneffekt und nicht der eigentlich Sinn hinter dem Singleton Pattern ist). Mehr dazu hier oder hier. Fazit: Globale Variablen und Singletons sind nicht immer schlimm. Aber sie werden praktisch immer falsch verwendet.

@dot: so wie ich dich verstanden habe, hat am ende dann aber doch jedes renderobject die topologischen daten gespeichert?

Nein warum? Natürlich erlaubt dir dieses Design das so zu machen wenn du willst. Dein Cube Objekt das sich ja um das Erzeugen der konkreten Instanz kümmert kann so aber auch genauso eine Referenz auf die entsprechenden Daten an die Instanz weitergeben anstatt die Daten zu kopieren, was ja genau das ist was du wolltest oder!?

[...] ich initialisiere sie am anfang jetzt einfach global mit NULL und danach nach BurningWaves vorschlag mit einem if(!staticVar) im constructor auf den richtigen wert... seid ihr damit eher einverstanden?

Nein absolut gar nicht. Deine Daten sind offenbar keine globalen Daten, warum also alles daran setzen sie irgendwie in eine globale Variable zu pressen? Nichts spricht hier für eine globale Variable, weder scope noch lifetime deines Objektes. Btw: Wie kümmerst du dich darum dass dein Objekt wieder gelöscht wird?

n0_0ne

1x Contest-Sieger

  • »n0_0ne« ist der Autor dieses Themas
  • Private Nachricht senden

20

14.10.2010, 17:28

@dot:
1. Ich presse doch jetzt garnichts mehr in eine globale variable. Durch ein Prototype* Cube::cubePrototype = NULL; in der cube.cpp und dem deklarieren als private kann man sonst nirgends mehr auf die variable zugreifen, weder lesend, noch schreibend, nur innerhalb der klasse, was ja genau der gewünschte effekt ist.

2. RenderObject ist wie gesagt abstrakt, ich kann also kein RenderObject-objekt erzeugen. Ich verwende es eigentlich nur, um gemeinsam genutzte hilfsfunktionen an alle Kindklassen vererben zu können und Polymorphie nutzen zu können. Damit ich also eine RenderObject-std::list haben kann, und es mir egal sein kann, ob es jetzt Cubes oder Spheres sind. Deine Lösung würde so also nicht wirklich funktionieren.

3. Löschen: Nunja, so wie es jetzt ist, können die Cubes ja ganz normal gelöscht werden. der zu den cubes gehörende "Prototype" würde allerdings bis zum Ende des Programms bestehen bleiben (wenn er einmal gebraucht wurde, ansonsten gibt es ihn nicht). Das ist wirklich nicht unbedingt optimal. Es gibt eigentlich keine andere Möglichkeit, als eine weitere statische methode, die dann den Prototypen löscht. Dazu müsste ich dann aber sicher sein, dass es keine Cube-Objekte mehr gibt, was nicht ganz so einfach zu bestimmen ist. Ich müsste wieder eine statische variable einbauen, die die anzahl der objekte zählt (also im ctor: ++counter, im dtor: --counter) und nur dann den prototype löschen, wenn der counter 0 ist.
Zugegeben, nicht die einfachste lösung, aber meiner meinung nach recht sauber.

Werbeanzeige