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

TigerClaw25

unregistriert

21

12.07.2017, 15:25

Ich glaube, wenn ich mal mit Zeigern als Rückgabetyp einer Funktion arbeiten würde, würde ich einfach innerhalb der Funktion einfach über "new" Speicher auf dem Heap reservieren. Dann kann ich selber bestimmen, wann dieser wieder freigegeben wird oder ich nutze statische Variablen, falls diese den Aufruf zählen soll. Zumindest habe ich verstanden, was das eigentliche Problem ist. Eine kurze Frage zu char-Arrays, ohne ein neues Thread zu beginnen. Darf man char-Arrays einfach kopieren? bei int-Arrays kann ich nicht einfach sagen "intArray1 = intArray2", das geht ja nur Elementweise [] über eine Schleife. Aber bei char-Arrays zählt ja bekanntlich nur die Anfangsadresse, also darf ich " char Array1[]="Hallo;" " einem zweiten Array zuweisen mit "Array1=Array2" oder? Elementweise oder mit dem Sternchen-Operator geht das. Aber in einem Buch habe ich gelesen, dass das Zuweisen eben nicht möglich sei, und deswegen strings genutzt werden. Das Argument finde ich aber nicht nachvollziehbar.

Ich bin per Zufall auf dieses Buch hier gestoßen: Beginning C++ Through Game Programming. Hat da jemand Erfahrung bzw. in wie weit unterscheidet es sich von Heiko's Buch inhaltlich?

Ich habe mir zu Übungszwecken das Buch SDL game Development bestellt. Eventuell hilft mir ein bishen Praxis eher weiter :)

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »TigerClaw25« (12.07.2017, 15:33)


David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

22

12.07.2017, 16:21

int-Arrays und char-Arrays unterscheiden sich nicht großartig voneinander.
Nein, Arrays kann man nicht zuweisen. Das ist halt so.

C-/C++-Quelltext

1
2
3
char charArray1[] = "hallo";                      // Variante 1
char charArray2[] = {'h', 'a', 'l', 'l', 'o', 0}; // Variante 2, bewirkt dasselbe
int intArray[] = {1, 2, 3, 47, 1337};             // und so initialisiert man ein int-Array

Das hier sind keine Zuweisungen, sondern Initialisierungen. Initialisieren geht nur einmal - nämlich da, wo du das Array deklarierst. Danach nicht mehr, dann musst du elementweise zuweisen oder mit memcpy, strcpy etc.

TigerClaw25

unregistriert

23

12.07.2017, 17:32

Hab mir jetzt angewöhnt, in einem leeren Heft zu jedem Thema Notizen zu sammeln, auf was geachtet werden sollte. Das die Zuweisung dann nur Elementweise geht, habe ich durch cin >> string; bereits gemerkt.

Was mir beim Thema Zeiger, aber auch Strings aufgefallen ist, ist folgendes:

C-/C++-Quelltext

1
2
char *pZeiger = {"Hallo"};
cout << pZeiger << endl;  // hier vergesse ich immer, das Sternchen nur bei Zugriff auf Array-Element oder einem anderen einzigen Wert verwendet wird. Bei char-Arrays fällt das weg, da ich für die Ausgabe Anfangsadresse benötige; so in cout definiert


Oft wird einfach die Deklaration und Initialisierung eines char-Arrays übersprungen und dem zeiger direkt ein String zugewiesen. Das bedeutet, dass das char-Array Text keine Namen hat. Wenn der Zeiger dann auf eine andere Adresse zeigen würde, könnte ich auf den Text ohne eine Bezeichnung überhaupt nicht mehr zugreifen. Was gehört zum guten Stil? Das obere Beispiel oder das hier:

C-/C++-Quelltext

1
2
3
char charArray[] = "Hallo";
char *pZeiger = charArray;
cout << pZeiger << endl;


Ein anderes Beispiel ist das hier

C-/C++-Quelltext

1
int *pZeiger = new int;

oder

C-/C++-Quelltext

1
2
int *pZeiger = nullptr;
pZeiger = new int;


Vielleicht ist das ja trivial, aber immerhin bringt mich das ein ganzes Stück weiter. Bisher habe ich nicht verstanden, wieso ich beispielsweise bei try/catch für " throw "Irgend ein Text" " bzw. dem catch-Teil als Parameter "catch (char *Fehlerstring)" schreiben muss. Mittlerweile weiß ich, dass ich einen Zeiger benötige, der eben auf die Anfangsadresse des String-Arrays zeigt, dass ich übergebe. Hier jedoch ebenfalls ein nameloses String.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

24

12.07.2017, 18:10

Das 4te Beispiel ist Unsinn. Es hat überhaupt keinen Zweck einen Pointer mit nullptr zu initialisieren, wenn du danach ohnehin was anderes zuweist.
Das 3te Beispiel hat wenig mit gutem Stil zu tun, sondern ist einfach eine dynamische Speicherallokation. Nicht mehr und nicht weniger.
Das 2te Beispiel ist überflüssiger Quatsch, weil du deinen char* charArray (denn nichts anderes ist das) erst einem neuen char* zuweist, um ihn dann auszugeben. Was soll da der Mehrwert sein?
"Guter" Stil wäre meiner Meinung nach:
const char* text = "mein Text"; // man bemerke das const
std::cout << text << std::endl; // man bemerke das explizite "std::"

Noch besser wäre wohl char* komplett wegzuwerfen und std::string zu verwenden, denn der ist für C++ explizit erfunden worden.

Beispiel 3 und 4 haben übrigens keinerlei Bezug zu 1 und 2. Das sind ganz andere Dinge, die da getan werden. Während 1 und 2 sich damit beschäftigen, dass du noch nicht verstehst, dass ein C-String nichts anderes ist als char* und ein char* nichts anderes als ein char[] und wie Pointer eigentlich genau funktionieren, beschäftigen sich 3 und 4 mit dynamischer Speicherallokation.

Bei deinem Absatz über try/catch würfelst du auch wieder einiges durcheinander. Bitte lies dein Buch noch einmal langsam und gründlich über diese Kapitel. catch hat relativ wenig mit char* zu tun. Ich kann dir auch einen int werfen oder einen std::runtime_error und dann? Weißt du, was du dann im catch tun müsstest?
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]

Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von »BlueCobold« (12.07.2017, 18:20)


TigerClaw25

unregistriert

25

13.07.2017, 09:11

Dass die beiden Beispiele nichts miteinander zutun haben, weiß ich. Ich wollte nur nicht mehrere Beiträge dazu verfassen.

Dass char* nichts anderes als char[] ist, weiß ich auch. Deshalb dereferenziert man auch bei Zeigern beispielsweise mit "*" oder mit "[]".

Zum Thema catch war meine Aussage lediglich auf "char*" bezogen. Bei einem "int" würde ich "catch(int i)" schreiben oder bsp. bei Klassenobjekten als Referenz "catch(int &i)".

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

26

13.07.2017, 11:25

Woher weißt du, ob es eine Klassenobject ist oder nicht? ;) (wie ist ein int eigentlich ein "Klassenobjekt"? Meintest du ein Objekt-Attribut? Wo ist der Unterschied für dich zwischen einem int-Attribut und einer lokalen int-Variable?) Für throw/catch gibt es eine einfache Regel: Throw by value, catch by reference.

Und bitte mach für verschiedene Diskussions-Themen auch ein neues Forums-Thema. Genau dafür sind sie da.

Dass char* nichts anderes als char[] ist, weiß ich auch. Deshalb dereferenziert man auch bei Zeigern beispielsweise mit "*" oder mit "[]".
Ja, aber darüber hinaus ist ein "Text" als C-String eben auch nichts anderes als ein char*. Du schienst etwas verblüfft zu sein, dass man einem Zeiger einen String zuweisen kann. Ein String ist aber auch nur ein eine Menge Zeichen, die über einen char* adressiert werden. Folglich sorgt man nur dafür, dass ein Zeiger auf dieselbe Adresse zeigt wie der String selbst.
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]

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »BlueCobold« (13.07.2017, 11:31)


TigerClaw25

unregistriert

27

22.07.2017, 09:36

Jetzt habe ich doch noch mal eine Frage zu Singletons:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#ifndef TSINGLETON
#define TSINGLETON

template <class T>
class TSingleton
{
    protected:

        // Membervariablen
        static T *m_pSingleton;   // Statisches Objekt

    public:

        // Memberfunktionen

        // Destruktor
        //
        virtual ~TSingleton ()
        {
        }

        // Get
        //
        // Aufgabe: Wenn nötig, statisches Objekt erzeugen und
        // Zeiger darauf zurückgeben
        //
        inline static T* Get ()
        {
            // Existiert schon eine Instanz?
            if (!m_pSingleton)
                m_pSingleton = new T;   // Nein, dann neue Instanz erzeugen

            // Zeiger auf die Instanz zurückgeben
            return (m_pSingleton);

        } // Get

        // Statisches Objekt freigeben
        //
        static void Del ()
        {
            // Gab es eine Instanz?
            if (m_pSingleton)
            {
                delete (m_pSingleton);  // Ja, dann freigeben
                m_pSingleton = NULL;    // und Zeiger auf NULL setzen
            }

        } // Del

};

// Die statische Variable erzeugen
//
template <class T>
T* TSingleton<T>::m_pSingleton = 0;

#endif


Das Erzeugen der statischen Variablen erfolgt "global" mit "T* TSingleton<T>::m_pSingleton = 0;". Aber ist der Zugriff dann auch global möglich und durch die Angaben innerhalb der Klassendeklaration wie "public" beschränkt?

Meine zweite Frage: Wieso gibt man die Adresse in der Funktion "inline static T* Get " zurück? Wenn ich die statische Variable public halten würde, nur als Beispiel, und die Funktion ohne Zeigerrückgabe umändere, dann ist der Compiler nicht einverstanden. Ich wollte es ohne Zeigerrückgabe versuchen, also statt

C-/C++-Quelltext

1
2
    // Eine Statusmeldung ins Logfile schreiben
    CLogfile::Get()->Statusmeldung ();

mit

C-/C++-Quelltext

1
2
    CLogfile::Get(); // Einfach aufrufen der Funktion und erzeugen der Instanz
m_pSingleton->Statusmeldung (); // Singleton ist ja dann public


aberr ohne Rückgabe des Zeigers funktioniert es dennoch nicht. Dachte das statische Objekt exisiert überall für Kklassen und ich muss nicht mehr mit Rückgabewerten arbeiten, sondern lediglich die Funktion aufrufen und dann direkt auf Variable zugreifen.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

28

22.07.2017, 10:17

Du verwechselst hier schon wieder tausend Sachen miteinander. Ich weiß nicht, ob du das Buch nur überfliegst oder nur auf den Code schaust und nicht auf die Beschreibungstexte. Global hat nichts mit statisch zu tun und keins davon damit, wie man von außen auf etwas zugreift. Das sind komplett verschiedene Dinge.
- statisch: Das Eigenschaft (eines Objekts) exisitiert unabhängig von den Instanzen einer Klasse und ist somit für alle dieselbe
- global: Eine Deklaration, auf die jeder überall zugreifen kann. "m_pSingleton" ist nicht global, es ist lediglich definiert worden, genau wie Methoden einer Klasse auch definiert werden. Das heißt nicht, dass jeder darauf zugreifen darf. Deklaration != Definition.
- private/protected/public: Schränken den Zugriff auf ein internes Detail einer Klasse nach außen ein oder genehmigen ihn

Die Variable "m_pSingleton" ist als protected deklariert und nicht als public. Das heißt nur die Singleton-Klasse und davon abgeleitete dürfen direkt auf diese Eigenschaft zugreifen. Mal davon abgesehen, dass du sowieso den Scope vergessen hast. Also wenn, dann müsstest du auf TSingleton<HierDerKlassenTyp>::m_pSingleton zugreifen und nicht nur auf m_pSingleton.
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]

TigerClaw25

unregistriert

29

22.07.2017, 14:53

Den scope hatte ich vergessen. Der wird ja verwendet, weil auf Methoden und Membervariablen nicht über Instanzen zugegriffen wird.

Das mit global habe ich auch verstanden. Diese wird einmalig deklariert und definiert. Bei statischen Membervariablen erfolgt die Deklaration innerhalb der klasse, wo auch Zugriffs Rechte gesetzt werden über public, etc.. Definition erfolgt dann wie global,aber eben nur für Basis und Klassen die erben. Das wollte ich nur bestätigt haben, dass das so richtig ist.

Was mich etwas verwirrt ist das zurückgeben des Zeigers. Man haette die Funktion ja auch nur zum erzeugen einer neuen Instanz nehmen können und für den Zugriff auf Zeiger auf Objekt ejne andere Funktion. Aber ich glaube ohne Rückgabe des Zeigers wjrd der Aufruf schwer, da die Adresse nach dem reservieren von Speicher durch new ja benötigt wird, über später die Funktionen der klasse der Instanz aufzurufen.Aber andere Möglichkeiten gebe es bestimmt auch ohne Rückgabe des Zeigers.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

30

22.07.2017, 15:12

Du kannst problemlos aus der einen Funktion zwei machen. Aber was hast du dann davon? Dann musst du überall, wo du das Singleton verwendest, zwei Methoden aufrufen. Zumindest wäre das so, wenn das Singleton korrekt eingesetzt werden würde. Das wird nämlich nur dann eingesetzt, wenn man nicht so einfach sicherstellen kann, dass man von einer gewissen Klasse nur eine einzige Instanz hat, egal was passiert. Wenn du also wüsstest, dass du die Funktion zum Erzeugen der Instanz nur einmal aufrufen musst und danach immer 'get' benutzen kannst, dann hast du effektiv:
1) Das Problem überhaupt nicht mehr, für dessen Lösung das Singleton überhaupt erst erfunden wurde
und
2) Mit einer einfachen globalen Variable eine viel genauere Abbildung dessen, was du eigentlich willst

Das Buch verwendet das Singleton schlicht falsch. Eine globale Variable wäre genau das gewesen, was hätte eingesetzt werden sollen. Und ja, das ist schlecht. Das Singleton zu missbrauchen ist aber noch schlechter.

Davon mal ganz abgesehen, was wäre der Sinn das in zwei Methoden aufzuteilen? Dann musst du plötzlich extern die Logik aufrufen, die die Klasse ja eigentlich wegkapseln wollte.
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]

Werbeanzeige