PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Ein paar Fragen zu Pointer und Funktionen in C++


pajofego
2005-05-30, 21:10:52
Hallo Leute ich bin's mal wieder mit Fragen rund um C++ :eek:

Folgender Beispielcode:


double GetValue_1()
{
// ... mach was!!!
return irgendetwas;
}

double GetValue_2(double *value)
{
// ... mach was!!!
return irgendetwas;
}

void DoSomething()
{
for(int i = 0; i<1000; i++)
{
double h_value_1 = GetValue_1();
// ...
double h_value_2 = GetValue_2(&h_value_1);
// ...
}
}


Prizipiell ist es so, dass ich in einer größeren Schleife Funktionen aufrufe, dessen Output wiederum der Input einer anderen Funktion ist. Jetzt habe ich noch im Kopft, dass es klüger ist, anstatt ständig den Wert, die Adresse des Inputs einer Funktion zu übergeben, um ein bischen Geschwindigkeit rauszuholen. Problem ist jetzt nun, so wie ich es oben gelöst habe, ich den Output einer Funktion zwischenspeichere und dessen Adresse an die nächste Funktion weitergebe und somit sicherlich nichts dabei gewonnen habe.

Ich würde ganz gerne soetwas machen, d.h. die Adresse des Outputs der Funktion weitergeben. Dabei aber mekert der Compiler:

double h_value_2 = GetValue_2(&GetValue_1());


Was muss ich da anders machen, damit mein Vorhaben klappt? Hättet ihr da ein paar Tipps? Lohnt sich eigentlich der Aufwand mit der Übergabe der Adresse anstatt einer Kopie des Wertes weiterzugeben?

Recht schönen Dank

Gruß

pajofego

Coda
2005-05-30, 21:20:31
Bei sowas würde ich mir keine großen Sorgen machen, das optimiert auch der Compiler größtenteils selbstständig.

Bei einem double verlierst du sogar eher Geschwindigkeit wenn du das Ding als Referenz oder Pointer übergibst. Bei einem float/int ist es sogar absolut kontraproduktiv. Das lohnt sich eigentlich nur bei größeren Strukturen/Klassen.

pajofego
2005-05-30, 21:28:34
Ach so! O.K. umso besser, dass bereitet mir dann auch weniger Kopfschmerzen. :biggrin:

Gruß

pajofego

ScottManDeath
2005-05-30, 21:30:10
Hallo Leute ich bin's mal wieder mit Fragen rund um C++ :eek:

Folgender Beispielcode:


double GetValue_1()
{
// ... mach was!!!
return irgendetwas;
}

double GetValue_2(double *value)
{
// ... mach was!!!
return irgendetwas;
}

void DoSomething()
{
for(int i = 0; i<1000; i++)
{
double h_value_1 = GetValue_1();
// ...
double h_value_2 = GetValue_2(&h_value_1);
// ...
}
}


Prizipiell ist es so, dass ich in einer größeren Schleife Funktionen aufrufe, dessen Output wiederum der Input einer anderen Funktion ist. Jetzt habe ich noch im Kopft, dass es klüger ist, anstatt ständig den Wert, die Adresse des Inputs einer Funktion zu übergeben, um ein bischen Geschwindigkeit rauszuholen. Problem ist jetzt nun, so wie ich es oben gelöst habe, ich den Output einer Funktion zwischenspeichere und dessen Adresse an die nächste Funktion weitergebe und somit sicherlich nichts dabei gewonnen habe.

Ich würde ganz gerne soetwas machen, d.h. die Adresse des Outputs der Funktion weitergeben. Dabei aber mekert der Compiler:

double h_value_2 = GetValue_2(&GetValue_1());


Was muss ich da anders machen, damit mein Vorhaben klappt? Hättet ihr da ein paar Tipps? Lohnt sich eigentlich der Aufwand mit der Übergabe der Adresse anstatt einer Kopie des Wertes weiterzugeben?

Recht schönen Dank

Gruß

pajofego



Prinzipiell ist es Aufgabe des Compilers die unnötigen temporären Variablen wegzuoptimieren. Stichwort RVO (return value optimization) und NRVO (named return value optimization).

Unter C++ übergibt man Parameter üblicherweise mittels const T& param , man muss dadurch nicht dauern * und -> schreiben.



double GetValue_1()
{
// ... mach was!!!
return irgendetwas;
}

double GetValue_2(const double& value)
{
// ... mach was!!!
return irgendetwas;
}

void DoSomething()
{
for(int i = 0; i<1000; i++)
{
double h_value_2 = GetValue_2(GetValue_1());
}
}


Bei float, int, char ... ist die Parameterübergabe by value am günstigsten da der Compiler diese in Registern ablegen kann ( z.b. int in eax, float in ST(0)). Bei größeren Objekten ( z.B. Matrizen) die größer als ein Zeiger sind (4 Byte unter 32 Bit Systemen, 8 Byte unter 64 Bit Systemem) sollte man by reference bevorzugen. Double sollte man auch by value machen, da es AFAIK auch in FPU Registern übergeben wird.

Unabhängig davon gilt: premature optimization is the root of all evil, also zuerst machen dass es läuft, danach benchmarken und dann erst die Flaschenhälse optimieren.

pajofego
2005-05-30, 22:50:32
Danke an euch beiden für die kleine und sehr hilfreiche Lehrstunde in Sachen C++.

Da wir gerade beim Thema Optimieren sind. Z.Zt. code ich in DEV C++. Gibt es evt. kostenlose Analyseprogramme, mit dem man nachschauen kann wo und wieviel Zeit in welcher Prozedur/Funktion verbraten wird? Es soll eine sehr Zeitkritische Anwendung werden und da ist jedes Zehntel, das ich rausholen kann von Vorteil.

Danke,

Gruß

pajofego

Trap
2005-05-30, 23:18:19
Wenn Dev-C++ keine Option in der GUI für profiling hat:
http://www.cs.utah.edu/dept/old/texinfo/as/gprof_toc.html beschreibt wie man den von Dev-C++ benutzten compiler dafür verwendet.

ScottManDeath
2005-05-31, 00:01:27
Ich hatte mal vor einiger Zeit mit dem AMD Codeanalyst gearbeitet.

GloomY
2005-05-31, 01:22:57
Ich würde ganz gerne soetwas machen, d.h. die Adresse des Outputs der Funktion weitergeben. Dabei aber mekert der Compiler:

double h_value_2 = GetValue_2(&GetValue_1());
Eine Funktion ist keine Variable. An der Adresse der Funktion steht der Code von dieser und nicht der Rückgabewert. Dieser wird üblicherweise über den Stack übergeben, d.h. die Adresse dieses Rückgabewerts ist dynamisch, je nachdem wo der Stackpointer gerade steht.

Wenn GetValue_2 statt einem Pointer auf ein double einen Pointer auf eine Funktion, die ein double zurückliefert, bekäme, könnte man es folgendermaßen machen:
double GetValue_1() {
// ... mach was!!!
return irgendetwas;
}

double GetValue_2(double (*value)()) {
// ... mach was!!!
double test = (*value)();
return irgendetwas;
}

void DoSomething() {
double (*fp)();
fp = &GetValue_1;
for(int i = 0; i<1000; i++) {
// ...
double h_value_2 = GetValue_2(fp);
// ...
}
}Das ganz ist allerdings nicht von mir getestet.

Und wie bereits oben erwähnt macht ein guter Compiler sowieso Function-Inlining und andere Optimierungen.

zeckensack
2005-05-31, 04:11:33
Err ... GloomY ...
Die Adresse der Funktion ist GetValue_1, ohne Klammern, und ohne "address of"-Operator. Mit Klammer dahinter ist natürlich der Aufruf der Funktion. Zusätzlich noch mit "address of" gibt's nicht, Compiler-Fehler ahoi.
Das wäre die Adresse eines Funktionsaufrufs mit konkreten Parametern, und das ist kein sinnvolles Konstrukt.

Du Schuft hast editiert! ;(
Das kann ich auch: Ich sehe gerade dass mein Compiler &GetValue_1 auch schluckt, und als Äquivalent zu GetValue_1 behandlet. Hrm.

micki
2005-05-31, 05:45:43
Unter C++ übergibt man Parameter üblicherweise mittels const T& param , man muss dadurch nicht dauern * und -> schreiben.


der eigentliche Grund ist aber, dass eine referenze immer gefüllt ist, während ein pointer ein nullpointer sein könnte und man zur sicherheit darauf testen sollte (ASSERT)

my2klugscheissCent

MfG
micki

maximAL
2005-05-31, 11:14:00
Da wir gerade beim Thema Optimieren sind. Z.Zt. code ich in DEV C++. Gibt es evt. kostenlose Analyseprogramme, mit dem man nachschauen kann wo und wieviel Zeit in welcher Prozedur/Funktion verbraten wird?

Projekt Optionen -> Compiler -> Code Profiling -> erzeuge Auslastungsinfor zur Analyse [yes]
alles neu erstellen, einmal laufen lassen
Ausführen -> Profil Analyse

Coda
2005-05-31, 12:47:01
Das kann ich auch: Ich sehe gerade dass mein Compiler &GetValue_1 auch schluckt, und als Äquivalent zu GetValue_1 behandlet. Hrm.Ja, ist beides erlaubt :)
D.h. es ist steht in der Spezifikation und es macht nicht nur dein Compiler so.

pajofego
2005-05-31, 23:34:02
Hey Super,

dass sich hier viele an der Diskussion beteiligen...Danke

Schön, dass Dev C++ dieses Tool(Code Profiling) schon mit an board hat. Dev C++ gefällt mir bis auf ein paar Macken sehr gut. Vor allem nervt mich der Editor! Habt ihr auch Probleme den Quelltext vernünftig einzurücken? Bei mir hat jede Zeile eine Unterschiedliche Tablänge. Mal lang mal kurz...verstehe ich nicht ganz, obwohl ich unter Werkzeuge->Editor Optionen, die Tablänge auf 2 gestellt habe :|

BTW:

Ich versuche die ganze Zeit schon einen Pointer auf eine Funktion nach folgendem Schema zu setzen:

// Im protected Abschnitt -> Header File
protected:
virtual double GetValue_1(double inp_1);
virtual double GetValue_2(double inp_2);
// ..
private:
double (*MeineFunktion)(double);

// CPP-File
// Im Konstruktor folgt folgende Anweisung
MeineFunktion = GetValue_1;


In den meisten Büchern wird's so gemacht, nur ich bekomme ständig folgende Fehlermeldung:

" error: argument of type `double (clNOC_Pipe::)(double)' does not match `double (*)(double)' "

Ich denke einmal ich habe da mal wieder etwas Grundlegendes nicht verstanden...findet ihr noch Zeit mir das zu erklären?

Danke,

Gruß

pajofego

Gnafoo
2005-05-31, 23:41:30
Schön, dass Dev C++ dieses Tool(Code Profiling) schon mit an board hat. Dev C++ gefällt mir bis auf ein paar Macken sehr gut. Vor allem nervt mich der Editor! Habt ihr auch Probleme den Quelltext vernünftig einzurücken? Bei mir hat jede Zeile eine Unterschiedliche Tablänge. Mal lang mal kurz...verstehe ich nicht ganz, obwohl ich unter Werkzeuge->Editor Optionen, die Tablänge auf 2 gestellt habe :|


Vielleicht solltest du auch mal einen Blick auf die Code::Blocks-IDE werfen. Die gibt es noch nicht so lange, aber das was ich bisher davon gesehen habe scheint nicht übel zu sein. (http://www.codeblocks.org/)


Ich versuche die ganze Zeit schon einen Pointer auf eine Funktion nach folgendem Schema zu setzen:

// Im protected Abschnitt -> Header File
protected:
virtual double GetValue_1(double inp_1);
virtual double GetValue_2(double inp_2);
// ..
private:
double (*MeineFunktion)(double);

// CPP-File
// Im Konstruktor folgt folgende Anweisung
MeineFunktion = GetValue_1;


In den meisten Büchern wird's so gemacht, nur ich bekomme ständig folgende Fehlermeldung:

" error: argument of type `double (clNOC_Pipe::)(double)' does not match `double (*)(double)' "

Ich denke einmal ich habe da mal wieder etwas Grundlegendes nicht verstanden...findet ihr noch Zeit mir das zu erklären?


Ich glaube das geht so gar nicht, weil die Methode nicht static ist. Kann aber sein, dass noch was anderes faul ist. Was Funktionspointer angeht verweise ich immer gerne auf http://www.newty.de/fpt/index.html. Die haben auch einiges zu C++ geschrieben.

cu DerTod

maximAL
2005-06-01, 11:01:33
Mal lang mal kurz...verstehe ich nicht ganz, obwohl ich unter Werkzeuge->Editor Optionen, die Tablänge auf 2 gestellt habe :|
vielleicht hilfts, wenn du die intelligenten tabs abstellst...

ScottManDeath
2005-06-01, 16:01:47
Hey Super,
Ich versuche die ganze Zeit schon einen Pointer auf eine Funktion nach folgendem Schema zu setzen:

// Im protected Abschnitt -> Header File
protected:
virtual double GetValue_1(double inp_1);
virtual double GetValue_2(double inp_2);
// ..
private:
double (ClassName::*MeineFunktion)(double);

// CPP-File
// Im Konstruktor folgt folgende Anweisung
MeineFunktion = &GetValue_1;



Das Ganze nennt sich Pointer To Member. Ich schlage vor dass Du für deine PTMs typedefs machst, dann ist das weniger hässlich zu schreiben. So in der Art:


typedef double (ClassName::*PointerToMemberType)(double);

PointerToMemberType m_meine_funktion;

und dann im ctor:

m_meine_funktion = & GetValue_1;



Man sollte den & operator immer mit schreiben, dann ist es explizit was man will und der Compiler kommt nicht in Schwulitäten ;)

Coda
2005-06-01, 16:17:38
Das ist laut Spezifikation auch so explizit.

ScottManDeath
2005-06-01, 17:16:48
Ich war mir nicht ganz sicher ob das "nur" dem Style Guide oder dem C++ Standard. IIRC war es bi VC 6.0 noch möglich das & wegzulassen. Naja egal, ein & mehr tut nicht weh ;)

zeckensack
2005-06-01, 19:02:10
Ich war mir nicht ganz sicher ob das "nur" dem Style Guide oder dem C++ Standard. IIRC war es bi VC 6.0 noch möglich das & wegzulassen. Naja egal, ein & mehr tut nicht weh ;)MingW/GCC 3.2 frisst auch beides.
Ein Funktionsname ohne Klammern kann kein Funktionsaufruf sein. Deswegen ist die Syntax auch ohne "&" schon eindeutig.

pajofego
2005-06-01, 23:35:10
Danke es funktioniert!

Die dumme Sache mit den Tabs ist auch gelöst! Man muss unter Editor Optionen die "smart tabs" ausschalten ;)

Gruß

pajofego

Coda
2005-06-01, 23:43:11
Mal etwas OT: Ist eigentlich irgendwas bezüglich besserer Memberfunktionspointern (Delegates?) in C++0x bekannt?

Mit boost::bind und boost::function kann man es zwar auch machen, ist aber etwas mühsam.

ScottManDeath
2005-06-02, 01:18:14
Mal etwas OT: Ist eigentlich irgendwas bezüglich besserer Memberfunktionspointern (Delegates?) in C++0x bekannt?

Mit boost::bind und boost::function kann man es zwar auch machen, ist aber etwas mühsam.

AFAIK nicht.

Die C++ Standard workgroup (http://www.open-std.org/jtc1/sc22/wg21/)hat Listen mit aktuellen Topics (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_status.html). Vielleich findest Du ja was.

C++/CLI hat delegates, jedoch nur für .NET. ist sicher nicht für jeden eine Option :(