 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Marcel Müller Guest
|
Posted: Sun May 20, 2007 12:18 am Post subject: Temporäres Objekt für Funktionsparamete r mit const T* |
|
|
Hallo,
ich habe folgende Situation:
struct MyArgs
{ //...
};
void foo(const MyArgs* param)
{
}
void bar(const MyArgs& param)
{ foo(¶m); // geht
}
int main()
{
foo(&MyArgs()); // geht nicht, Compilerfehler
bar(MyArgs());
foo(&(const MyArgs&)MyArgs()); // geht
return 0;
}
Leider compiliert das nicht:
test.cpp(9:7) : error EDC3058: Operand of "&" operator must be an lvalue.
Schön und gut, aber warum geht der indirekte Aufruf über bar() dann
fehlerfrei. Soweit ich weiß darf man jederzeit konstante Referenzen auf
temporäre Objekte übergeben und sogar innerhalb eines Blocks halten. Und
man darf mit & einen Pointer auf ein konstantes Objekt aus einer
konstanten Referenz machen. Warum geht das nicht in einem Rutsch?
Es scheint wohl auch vom Compiler abzuhängen. Gcc bringt zumindest nur
eine Warnung. Das andere war icc (IBM).
Hintergrund: ich wollte das für den Aufruf von Callback-Funktionen
(Events) verwenden, um die nötigen EventArgs-Strukturen in einem
Einzeiler zu basteln.
Und den Funktionsparameter der Events traue ich mich nicht auf eine
Referenz zu ändern, da der ganze Kram für das Backend auf void* und
zurück gecastet wird. Dadurch ist die zugrundeliegende Implementierung
kein Template und damit das Executable deutlich kleiner. Eine Cast von
(T*) nach (void*) und wieder nach (T*) ist ja garantiert. Und (void
(*callback)(T*)) nach (void (*callback)(void*)) und zurück geht
üblicherweise auch gut.
Aber mit Referenzen müsste das heißen (void (*callback)(T&)) nach (void
(*callback)(void&)), was natürlich Blödsinn ist. Und von (void
(*callback)(T&)) nach (void (*callback)(void*)) zu casten, ist mir
endgültig zu heiß, obwohl ich bisher keine Implementierung kenne, bei
der der tatsächliche, technische Aufruf mit einer Referenz sich von dem
mit einem Pointer unterscheidet.
Marcel |
|
| Back to top |
|
 |
James Kanze Guest
|
Posted: Mon May 21, 2007 2:07 pm Post subject: Re: Temporäres Objekt für Funktionsparameter mit const T* |
|
|
On May 19, 9:18 pm, Marcel Müller <news.5.ma...@spamgourmet.org>
wrote:
| Quote: | ich habe folgende Situation:
struct MyArgs
{ //...
};
void foo(const MyArgs* param)
{
}
void bar(const MyArgs& param)
{ foo(¶m); // geht
}
int main()
{
foo(&MyArgs()); // geht nicht, Compilerfehler
|
Genau. In Wörten der Norm ist MyArgs() kein lvalue.
| Quote: | bar(MyArgs());
foo(&(const MyArgs&)MyArgs()); // geht
return 0;
}
Leider compiliert das nicht:
test.cpp(9:7) : error EDC3058: Operand of "&" operator must be an lvalue.
Schön und gut, aber warum geht der indirekte Aufruf über bar() dann
fehlerfrei.
|
Weil der Parameter von bar ein lvalue ist.
| Quote: | Soweit ich weiß darf man jederzeit konstante Referenzen auf
temporäre Objekte übergeben und sogar innerhalb eines Blocks halten. Und
man darf mit & einen Pointer auf ein konstantes Objekt aus einer
konstanten Referenz machen. Warum geht das nicht in einem Rutsch?
|
Weil es verboten ist:-).
Die Grundregeln stammen aus C, wo du eigentlich nie die Adresse
einen Temporär bekommen kannst. Referenzen wurden in C++
eingefügt u.a. um überladene Operatore zu unterstützen, ohne zu
viele tiefen Kopien zu verlangen. Ein operator+ aber, worauf du
keinen Temporär als Parameter übergeben könnte, wäre nicht sehr
geschickt; also hat man erlaubt, Referenzen mit Temporären zu
initialisieren. Danach hat man bemerkt, dass es wohl zu
gefährlich ist, und hat es auf Referenzen an const beschränkt.
Nie aber hat man es für nötig gefühlt, diese Freiheit auch auf
Zeiger ausdehnen zu lassen. Der Grund des Unterschieds ist also
rein historisch.
| Quote: | Es scheint wohl auch vom Compiler abzuhängen. Gcc bringt zumindest nur
eine Warnung. Das andere war icc (IBM).
|
Von der Sprache her ist es absolut verboten.
Wenn es um den eingebauten Operator geht. Im Sonderfall kannst
du der Operator& überladen. Dann gilt es als einen
Funktionsaufruf, was auf einem Temporär erlaubt ist. Also:
struct MyArgs
{
// ...
MyArgs const* operator&() { return this ; }
} ;
Ich würde aber so was nur in ganz besonderen Fällen benutzen,
wenn überhaupt.
--
James Kanze (GABI Software) email:james.kanze (AT) gmail (DOT) com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
| Back to top |
|
 |
Stefan Reuther Guest
|
Posted: Mon May 21, 2007 3:23 pm Post subject: Re: Temporäres Objekt für Funktionspara meter mit const T* |
|
|
Marcel Müller wrote:
| Quote: | void foo(const MyArgs* param)
void bar(const MyArgs& param)
[...]
foo(&MyArgs()); // geht nicht, Compilerfehler
bar(MyArgs());
foo(&(const MyArgs&)MyArgs()); // geht
[...]
Leider compiliert das nicht:
test.cpp(9:7) : error EDC3058: Operand of "&" operator must be an lvalue.
Schön und gut, aber warum geht der indirekte Aufruf über bar() dann
fehlerfrei. Soweit ich weiß darf man jederzeit konstante Referenzen auf
temporäre Objekte übergeben und sogar innerhalb eines Blocks halten. Und
man darf mit & einen Pointer auf ein konstantes Objekt aus einer
konstanten Referenz machen. Warum geht das nicht in einem Rutsch?
|
"Ist halt so". Wenn du es in einem Rutsch haben willst, verpasse der
Klasse 'MyArgs' eine Funktion, die den this-Pointer rausrückt. Wenn du
es ganz schön haben willst, nenne diese Funktion 'operator&':
struct MyArgs {
const MyArgs* operator&() const { return this; }
MyArgs();
};
void foo(const MyArgs* param);
void bar(const MyArgs& param);
void x() {
foo(&MyArgs()); // geht jetzt
bar(MyArgs());
foo(&(const MyArgs&)MyArgs()); // geht
}
| Quote: | Und den Funktionsparameter der Events traue ich mich nicht auf eine
Referenz zu ändern, da der ganze Kram für das Backend auf void* und
zurück gecastet wird. Dadurch ist die zugrundeliegende Implementierung
kein Template und damit das Executable deutlich kleiner. Eine Cast von
(T*) nach (void*) und wieder nach (T*) ist ja garantiert. Und (void
(*callback)(T*)) nach (void (*callback)(void*)) und zurück geht
üblicherweise auch gut.
|
Da kannst du immer noch einen Wrapper drumbasteln, der aus den
Referenzen Zeiger macht und umgekehrt (eben sowas wie deine Funktion
'bar'). Als inline-Template o.ä. sollte das nichtmal Code generieren.
Stefan |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|