PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C++ Arbeiten mit globalen Variablen kontra Variablenübergabe im Function Header



BlueJay
20-10-2004, 11:59
Hallo Leute,

ich bin zwar so "erzogen" worden, globale Variable zu vermeiden, habe mittlerweile dabei aber so meine Bedenken:

Gegeben: ein mehr oder weniger großes Integerfeld, ein weiteres, nahezu gleichgroßes Integerfeld, um bestimmte Daten "herauszufischen".

Als Globale eignen sich die Felder selbst sowie deren Größen.

Irgendwie scheint es mir resourccenschonender und damit auch bestimmt schneller, diese als Globale zu verwenden.

Praktisches Beispiel mit Globalen:



#define XMAX wattauchimmer
#define YMAX nochsonviech
...
int f[XMAX*YMAX],liste[LMAX];
...

int get_nachbarn(int start)
{
int i,k,farbe=f[liste[1]],ende=liste[0],smax=XMAX*YMAX,xgr=XMAX-1;
for (i=start; i<=ende; i++)
{
k=liste[i]+1; if (k%XMAX>0) if (f[k]==farbe) add_liste(k,liste);
k=liste[i]-1; if (k%XMAX<xgr) if (f[k]==farbe) add_liste(k,liste);
k=liste[i]+XMAX; if (k<smax) if (f[k]==farbe) add_liste(k,liste);
k=liste[i]-XMAX; if (k>=0) if (f[k]==farbe) add_liste(k,liste);
}
return liste[0];
}


kontra so was hier, wo der ganze Rattenschwanz von Parametern sich im Header drängeln:




int get_nachbarn(int start,int xmax,int ymax,int f[],int liste[])
{
int i,k,farbe=f[liste[1]],ende=liste[0],smax=xmax*ymax,xgr=xmax-1;
for (i=start; i<=ende; i++)
{
k=liste[i]+1; if (k%xmax>0) if (f[k]==farbe) add_liste(k,liste);
k=liste[i]-1; if (k%xmax<xgr) if (f[k]==farbe) add_liste(k,liste);
k=liste[i]+xmax; if (k<smax) if (f[k]==farbe) add_liste(k,liste);
k=liste[i]-xmax; if (k>=0) if (f[k]==farbe) add_liste(k,liste);
}
return liste[0];
}


Die Globalen werden so, wie sie jeweils anfallen, noch von -zig anderen Functions verarbeitet.

Ich suche den schnellsten und ressourcenschonendsten Weg, nicht den elegantesten, denn wichtig ist vor allem, dass mir kein Usergeklicke dazwischenkommt, und dass die User nicht allzulange warten müssen.

Anmerkungen:
1. Bei langsamen Sprachen schalte ich die Eingabemöglichkeiten ab, während das Modul läuft.
2. der ganze Algo ist stabil und kommt immer irgendwann zum Ende.

Das Ganze läuft jetzt erst mal unter C++, aber Anmerkungen zu Javascript sind auch willkommen.

so long,
BlueJay

anda_skoa
20-10-2004, 16:14
Statt den Arrays könntest du std::vector nehmen, dann hast du implizit immer die Länge dabei.

Bei der Parameterübergabe bietet es sich zusätzlich an, Referenzen zu benutzen, also const & für Input-only und & für Input/Output Parameter.

Wenn mehrere Funktionen die selben Daten bearbeiten, ist vielleicht eine Gemeinsamkeit gegeben, die es erlaubt sie zu Methoden einer Klasse zu machen.
Dann könnten die Zahlenfelder Variablen dieser Klasse sein, müssen also nicht zwischen den Methoden übergeben werden.

Globale Daten sind immer problematisch, weil sie zu Abhängigkeiten zwischen Übersetzungeinheiten führen, was die ganze Software schwerer wartbar macht.

Ciao,
_

peecee
20-10-2004, 18:39
Du könntest dein globalen Arrays ja als static deklarieren.
Ich glaube das wäre der "beste" Weg.

BlueJay
21-10-2004, 14:02
Statt den Arrays könntest du std::vector nehmen, dann hast du implizit immer die Länge dabei.


Würde Sinn machen, wenn man die Länge extern manipulieren kann, etwa my_vec->length=4.
(bin erst seit August mit C/C++ zugange, der Algoblock, aus dem dies ist, ist aber erheblich älter)



Bei der Parameterübergabe bietet es sich zusätzlich an, Referenzen zu benutzen, also const & für Input-only und & für Input/Output Parameter.


schon richtig, aber ist das & nicht php-Syntax?
Mein C++ (gcc) macht das mit obigem Beispiel im Header schon ganz richtig als Referenzübergabe, ähnlich Javascript.



Wenn mehrere Funktionen die selben Daten bearbeiten, ist vielleicht eine Gemeinsamkeit gegeben, die es erlaubt sie zu Methoden einer Klasse zu machen.


wäre für das individuelle Programm die Klasse "simulation" :-), die ufert aber jetzt schon gerne aus mit ihren Spielregeln. Zunächst war dieser Algo tatsächlich Bestandteil der Klasse, weshalb ich f und l als Globale (dieser Klasse) angesehen habe. Dies meinte ich mit globaler Lösung.

Mittlerweile wird die Gruppe für verschiedene Simulationen angewendet, die nur gemeinsam haben, dass sie ihre Daten in f halten und nach der l(iste) manipulieren.



Globale Daten sind immer problematisch, weil sie zu Abhängigkeiten zwischen Übersetzungeinheiten führen, was die ganze Software schwerer wartbar macht.


Aus diesem Grund läuft es derzeit und auch wohl in Zukunft ohne Globale; schnell genug geht dieser Teil ja nach ersten Tests mit C++ über die Bühne, so dass ich diesmal nicht das Letzte herauskitzeln muss.

Ich habe vorher mit Javascript programmiert, und da war die Geschwindigkeit kritisch, der Ansatz mit den globalen Variablen machte die wenigsten Scherereien. An den Komfort, den das schnellere C++ bietet, muss ich mich erst gewöhnen :-)

so long,
BlueJay

BlueJay
21-10-2004, 14:12
Du könntest dein globalen Arrays ja als static deklarieren.
Ich glaube das wäre der "beste" Weg.

Du meinst, der ist *schneller* als die Datenübergabe im Funktionskopf?
Spart der (in C++) einen Zugriff auf irgendeinen Zeiger oder Referenz?

so long,
BlueJay

Boron
21-10-2004, 14:46
Wenn du eine Variable per Referenz übergibst, dann wird nur die Adresse im Hauptspeicher wo die Variable liegt übergeben.

Wenn du die Variable direkt übergibst, dann wird für die Ausführungszeit der Funktion eine Kopie der Variable angelegt.
Das Anlegen der Kopie ist langsamer als bei Übergabe per Referenz.

anda_skoa
21-10-2004, 17:51
schon richtig, aber ist das & nicht php-Syntax?

Kenne PHP diesbezüglich nicht genau genug.
Ich meinte das


void foo(string s);

Call-by-value



void foo(const string& s);

call-by-reference, input-only parameter



void foo(string& s);

call-by-reference, input-output parameter

In C++ nimmt man normalerweis für alles was kein primitiver Datentyp ist (int, char, double, usw.) eine Referenz oder einen Pointer.



Mittlerweile wird die Gruppe für verschiedene Simulationen angewendet, die nur gemeinsam haben, dass sie ihre Daten in f halten und nach der l(iste) manipulieren.

Wie wäre es mit einer Datenklassen, die die beiden Arrays zusammenfasst und entsprechende Zugriffsmethoden hat.
Dann kannst du die selben Daten an verschiedene Verarbeiter weitergeben, ohne viele Parameter zu brauchen.

Ciao,
_

BlueJay
21-10-2004, 17:58
Wenn du eine Variable per Referenz übergibst, dann wird nur die Adresse im Hauptspeicher wo die Variable liegt übergeben.

Wenn du die Variable direkt übergibst, dann wird für die Ausführungszeit der Funktion eine Kopie der Variable angelegt.
Das Anlegen der Kopie ist langsamer als bei Übergabe per Referenz.

Leuchtet ein, wenn ich an prall gefüllte Arrays (Pascal) denke.
Aber ich meine, irgendwo gelesen zu haben, dass, sobald ein Vektor im Prozedurkopf überreicht wird, nur der Pointer auf das erste Element übergeben wird. (Stroustrup Kap.7.2.1.)
Sollte doch dann Hose wie Jacke sein?

Oder gilt das Ganze auch für simple Integers?

so long,
BlueJay

BlueJay
22-10-2004, 10:41
In C++ nimmt man normalerweis für alles was kein primitiver Datentyp ist (int, char, double, usw.) eine Referenz oder einen Pointer.


Da hat Qt mich schon so "erzogen" :-), weil er zusammen mit GCC sonst schlicht die Zusammenarbeit verweigert. GCC brabbelt dann irgendwas von nicht-POD-Typen.
Zu den Arrays siehe meine Antwort an Boron.



Wie wäre es mit einer Datenklassen, die die beiden Arrays zusammenfasst und entsprechende Zugriffsmethoden hat.
Dann kannst du die selben Daten an verschiedene Verarbeiter weitergeben, ohne viele Parameter zu brauchen.


Also back to the roots :) Scheinbar sind "Globale" nicht verpönt, wenn sie nur in ihrer Klasse global sind. Das kommt meiner Faulheit sehr entgegen.

Trotzdem wird sich wohl die Variante mit dem Wasserkopf durchzusetzen, da sie verschiedene Felder und Listen bedienen kann, die demnächst innerhalb der Klasse Simulation oder auch woanders (Labyrinthgenerator) vorkommen können/werden.

Ich werde demnächst häufiger hier nachfragen, weil ich durch das Konvertieren der Programme zwar Praxis bekomme, aber nicht auf Anhieb den letzendlich optimalen Weg finde.

so long,
BlueJay

anda_skoa
22-10-2004, 15:44
Da hat Qt mich schon so "erzogen" :-), weil er zusammen mit GCC sonst schlicht die Zusammenarbeit verweigert. GCC brabbelt dann irgendwas von nicht-POD-Typen.

Was soll da nicht gehen?
Ich benutze das ununterbrochen in Zusammenhang mit Qt.

Ciao,
_

BlueJay
23-10-2004, 19:44
sofern du rein auf der Qt-Seite bleibst, geht es.

Aber schon printf meckert, wenn es statt eines Pointers einen (Q)String bekommt.

Und als ich in einer Function/Slot einen Dateipfad (als QString) bestimmen wollte, konnte ich ihn nur via Pointer an die "Klassenkameraden" weiterreichen. Das Ding war ausserhalb der Function immer noch undefinded, ganz einfach undefined.
Das war so der Zeitpunkt, ab dem ich nur noch mit Pointern gearbeitet habe.

Für Read-only (call-by-value) hingegen waren QStrings ok.

so long,
BlueJay

panzi
23-10-2004, 21:52
Aber schon printf meckert, wenn es statt eines Pointers einen (Q)String bekommt.
Wem wunderd's? Woher soll die ANSI C Funktion printf ein C++ Klasse aus Qt kennen? Ist ja auch garnicht möglich, da da printf eben C und QString C++ ist.
Man sollte weder C mit C++ noch ein Framework mit dem anderen mischen, bringt nur Probleme. Also wenn du Qt verwendest, verwendest du Qt und nicht ANSI C (und umgekehrt).

anda_skoa
24-10-2004, 13:36
sofern du rein auf der Qt-Seite bleibst, geht es.


Kann mir das schwer vorstellen, hatte noch nie Problem, weder mit C++ nocht mit C Code.



Aber schon printf meckert, wenn es statt eines Pointers einen (Q)String bekommt.

printf aus der C Stdlib?
Das kennt weder String noch Referenz, weil es in ANSI C weder Klassen noch Referenzen gibt.



Und als ich in einer Function/Slot einen Dateipfad (als QString) bestimmen wollte, konnte ich ihn nur via Pointer an die "Klassenkameraden" weiterreichen. Das Ding war ausserhalb der Function immer noch undefinded, ganz einfach undefined.

Den entsprechenden Code würde ich gerne mal sehen.



Das war so der Zeitpunkt, ab dem ich nur noch mit Pointern gearbeitet habe.

Spricht eigentlich auch nichts dagegen, außer dass man dann immer aus Nullpointer prüfen muss.

Ciao,
_

BlueJay
25-10-2004, 19:00
Den entsprechenden Code würde ich gerne mal sehen.


Der lebt nicht mehr, ist "umgepointert".
Wenn's dich brennend interessiert, es war die hiscore-Klasse in gamelib, wenn du eins von den späteren Qt-Programmen von meiner Seite nimmst (die, die den Pfad aus einer ini- Datei liest, z.B. Otashi / unter gentoo). Ich erinnere mich ganz dunkel, dass sich Suse9 und ein früherer Compiler (gcc 3.2.?) etwas anders verhielt und ich den Kram umschreiben musste für gentoo.

so long,
BlueJay