 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Hendrik Wendler Guest
|
Posted: Thu Sep 28, 2006 1:23 pm Post subject: konditionale stackobjekte |
|
|
Hi allerseits,
ich arbeite viel mit opengl. opengl ist eine
state engine. man setzt zum beispiel eine
farbe, und dann wird mit dieser farbe gezeichnet,
bis eine andere gesetzt wird. nichts neues.
in der praxis gibt es dutzende von states,
und manchmal sucht man stundenlang einen
fehler, weil irgendwo in der applikation ein state
gesetzt wurde, zum beispiel 'texturen an',
der anderwo gar nicht gelten soll. (aber noch gilt)
aus performance gründen ist es naturlich nicht
besonders gut, vor jedem zu zeichnenden punkt/linie/fläche
alle states zu setzen.
daher benutze ich gerne stackobjekte, die im
konstruktor einen state setzen und im destruktor
wieder löschen. beispiel:
class texenabler:
{
texenabler(){glEnable(TEX2D);}
~texenabler(){glDisable(TEX2D);}
}
das funktioniert bisher sehr gut, und funktioniert
auch bei exceptions etc.
function drawtextured_quad()
{
texenabler e;
draw_quad();
}
manchmal würde ich allerdings aus performancegründen
gerne auf die konstruktion eines solchen objektes
verzichten. (manche states sind teuer ...)
aber leider funktioniert das ja nicht:
function drawtextured_quad(bool texneeded)
{
if(texneede)
{
texenabler e;
}
draw_quad();
}
.... weil der destruktor ja schon nach der
if - abfrage aufgerufen wird. immer.
jetzt bliebe mir noch ein erweiteres objekt:
class texenabler:
{
texenabler(bool do_it=true){ if (do_it) glEnable(TEX2D);}
~texenabler(){glDisable(TEX2D);}
}
.... aber das gefällt mir nicht besonders aus diversen
gründen ... aus technischen interesse,
gibt es denn eine andere lösung für dieses problem?
besten gruss,
hendrik |
|
| Back to top |
|
 |
Olaf Krzikalla Guest
|
Posted: Thu Sep 28, 2006 9:58 pm Post subject: Re: konditionale stackobjekte |
|
|
Hi,
Hendrik Wendler wrote:
| Quote: | manchmal würde ich allerdings aus performancegründen
gerne auf die konstruktion eines solchen objektes
verzichten. (manche states sind teuer ...)
Dann willst Du auch nicht: |
function drawtextured_quad(bool texneeded)
{
std::auto_ptr<texenabler*> p (texneeded ? new texenabler() : 0);
draw_quad();
}
| Quote: | ... weil der destruktor ja schon nach der
if - abfrage aufgerufen wird. immer.
jetzt bliebe mir noch ein erweiteres objekt:
class texenabler:
{
texenabler(bool do_it=true){ if (do_it) glEnable(TEX2D);}
~texenabler(){glDisable(TEX2D);}
}
... aber das gefällt mir nicht besonders aus diversen
gründen ...
Warum eigentlich nicht? |
| Quote: | aus technischen interesse,
gibt es denn eine andere lösung für dieses problem?
Ich bin mir nicht sicher: |
class empty_struct {};
class texenabler: public empty_struct { /*...*/ };
function drawtextured_quad(bool texneeded)
{
const empty_struct& e = texneeded ? texenabler() : empty_struct();
draw_quad();
}
Die Frage ist hier, ob beide temporäre Objekte im ?: Ausdruck erzeugt
werden oder nur das jeweils gebrauchte (welches dann erst wieder mit der
Referenz ablebt, wenn der Compiler sein Handwerk versteht). Ich habe
dazu keine eindeutige Aussage gefunden, lediglich 5.16.1: "Only one of
the second and third expressions is evaluated." Aber 'evaluated' ist
nicht unbedingt 'constructed'.
MfG
Olaf Krzikalla |
|
| Back to top |
|
 |
Falk Tannhäuser Guest
|
Posted: Fri Sep 29, 2006 12:34 am Post subject: Re: konditionale stackobjekte |
|
|
Hendrik Wendler schrieb:
| Quote: | jetzt bliebe mir noch ein erweiteres Objekt:
class texenabler:
{
bool need_disable; |
public:
texenabler(bool do_it=true)
: need_disable(do_it)
{ if (do_it) glEnable(TEX2D); }
~texenabler() { if(need_disable) glDisable(TEX2D); }
};
sollte doch tun? Eventuell kannst Du der Klasse ja noch Methoden wie
enable() und disable() spendieren (welche natürlich dann 'need_disable'
aktualisieren), um innerhalb eines Blocks mit den "States" rumspielen zu
können. Die Boost-Thread-Leute machen's ja mit boost::mutex::scoped_lock
auch nicht anders.
MfG
Falk |
|
| Back to top |
|
 |
Heinz Ozwirk Guest
|
Posted: Fri Sep 29, 2006 12:49 am Post subject: Re: konditionale stackobjekte |
|
|
"Hendrik Wendler" <hendrik--nospam--@mxwendler.de> schrieb im Newsbeitrag
news:efg0sa$d87$00$1 (AT) news (DOT) t-online.com...
| Quote: | function drawtextured_quad(bool texneeded)
{
if(texneede)
{
texenabler e;
}
draw_quad();
}
... weil der destruktor ja schon nach der
if - abfrage aufgerufen wird. immer.
jetzt bliebe mir noch ein erweiteres objekt:
class texenabler:
{
texenabler(bool do_it=true){ if (do_it) glEnable(TEX2D);}
~texenabler(){glDisable(TEX2D);}
}
... aber das gefällt mir nicht besonders aus diversen
gründen ... aus technischen interesse,
gibt es denn eine andere lösung für dieses problem?
|
Ohne große Änderungen geht's mit einem Pointer:
void drawtextured_quad(bool texneeded)
{
std::auto_ptr<texenabler> e;
if (texneeded) e.reset(new texenabler);
draw_quad();
}
HTH
Heinz |
|
| Back to top |
|
 |
Andre Poenitz Guest
|
Posted: Fri Sep 29, 2006 1:40 am Post subject: Re: konditionale stackobjekte |
|
|
Hendrik Wendler <hendrik--nospam--@mxwendler.de> wrote:
| Quote: | aber leider funktioniert das ja nicht:
function drawtextured_quad(bool texneeded)
{
if(texneede)
{
texenabler e;
}
draw_quad();
}
|
Spricht was gegen
void drawtextured_quad(bool texneeded)
{
if (texneede) {
texenabler e;
draw_quad();
}
else {
draw_quad();
}
} |
|
| Back to top |
|
 |
Hubert Schmid Guest
|
Posted: Fri Sep 29, 2006 12:34 pm Post subject: Re: konditionale stackobjekte |
|
|
Hendrik Wendler <hendrik--nospam--@mxwendler.de> writes:
| Quote: | jetzt bliebe mir noch ein erweiteres objekt:
class texenabler:
{
texenabler(bool do_it=true){ if (do_it) glEnable(TEX2D);}
~texenabler(){glDisable(TEX2D);}
}
... aber das gefällt mir nicht besonders aus diversen
gründen ...
|
Ich finde es in Ordnung, dem Konstruktor ein Flag zu übergeben, ob die
Aktion tatsächlich ausgeführt wird. Das habe ich an manchen Stellen
auch schon verwendet. Und boost::mutex::scoped_lock macht das
beispielsweise auch so:
http://www.boost.org/doc/html/threads/concepts.html#threads.concepts.ScopedLock
--
Hubert Schmid - http://www.z42.de |
|
| Back to top |
|
 |
Johannes Mueller Guest
|
Posted: Fri Sep 29, 2006 2:44 pm Post subject: Re: konditionale stackobjekte |
|
|
Hubert Schmid <svyut4op48mg1sgh (AT) expire (DOT) z42.de> skribis:
| Quote: | Hendrik Wendler <hendrik--nospam--@mxwendler.de> writes:
jetzt bliebe mir noch ein erweiteres objekt:
class texenabler:
{
texenabler(bool do_it=true){ if (do_it) glEnable(TEX2D);}
~texenabler(){glDisable(TEX2D);}
}
... aber das gefällt mir nicht besonders aus diversen
gründen ...
Ich finde es in Ordnung, dem Konstruktor ein Flag zu übergeben, ob die
Aktion tatsächlich ausgeführt wird.
|
Ich mag solche bool flags nicht so wirklich. Ich würde da eher einen
enum nehmen.
class texenabler
{
public:
enum EnableFlag { DoNotEnable=0, DoEnable };
texenabler( EnableFlag ef = DoEnable )
{
if ( ef == DoEnable )
glEnable(TEX2D);
}
// ...
};
Dann wird der Code lesbarer:
texenabler( texenabler::DoNotEnable ); // ist klar
anstatt
texenabler( false ); // Was bedeutet false hier?
joh |
|
| Back to top |
|
 |
Hendrik Wendler Guest
|
Posted: Fri Sep 29, 2006 3:06 pm Post subject: Re: konditionale stackobjekte |
|
|
| Quote: | class texenabler:
{
texenabler(bool do_it=true){ if (do_it) glEnable(TEX2D);}
~texenabler(){glDisable(TEX2D);}
}
... aber das gefällt mir nicht besonders aus diversen
gründen ...
Warum eigentlich nicht?
|
Hi, danke für die Antworten!
es gefällt mir aus -naja, 'äthetischen' gründen?-
nicht besonders. ein objekt erzeugen, das via flag
mitgeteilt bekommt, das es eigentlich gar nicht da
sein sollte.
das zum einen, und -ganz trivial- dann habe ich ja
schon eine menge von diesen objekten in diversen
varianten. also faulheit.
der dritte grund wäre, das ich lieber im 'höheren'
code sichtbar habem würde, was passiert. das ist
(tut ja leider nicht) einfach lesbarer
if (needtextures)
{
texenabler e;
}
als
texenabler e(false);
.... da weiss man nach so einem jahr kaum noch,
was das 'false' bedeutet ...
Vielen Dank für die Tips,
Hendrik |
|
| Back to top |
|
 |
Daniel Albuschat Guest
|
Posted: Fri Sep 29, 2006 7:51 pm Post subject: Re: konditionale stackobjekte |
|
|
Hendrik Wendler wrote:
[nutzt opengl]
| Quote: | in der praxis gibt es dutzende von states,
und manchmal sucht man stundenlang einen
fehler, weil irgendwo in der applikation ein state
gesetzt wurde, zum beispiel 'texturen an',
der anderwo gar nicht gelten soll. (aber noch gilt)
aus performance gründen ist es naturlich nicht
besonders gut, vor jedem zu zeichnenden punkt/linie/fläche
alle states zu setzen.
daher benutze ich gerne stackobjekte, die im
konstruktor einen state setzen und im destruktor
wieder löschen. beispiel:
|
Sehr gute Idee.
| Quote: | class texenabler:
{
texenabler(){glEnable(TEX2D);}
~texenabler(){glDisable(TEX2D);}
}
das funktioniert bisher sehr gut, und funktioniert
auch bei exceptions etc.
|
Was mich an der Variante stört ist, dass die Verschachtelung
nicht funktioniert. Ich fände eine Lösung wie diese
irgendwo klüger, allerdings benötigt es einen zusätzlichen
OpenGL-Call zum Lesen des States:
class textmanager
{
private:
bool state;
textmanager(){ glGetBooleananv(GL_TEXTURE_2D,&state); }
~textmanager(){
if( state )
glEnable(GL_TEXTURE_2D);
else
glDisable(GL_TEXTURE_2D);
}
void enable(bool b = true) const {
if( b )
glEnable(GL_TEXTURE_2D);
else
disable();
}
void disable() const
{ glDisable(GL_TEXTURE_2D); }
}
(Ich habe GL_TEXTURE_2D und glGetBooleananv mal gerate, weiß nicht,
ob das in der Form möglich ist).
Zustätzlich könnte man den State noch selbst mitverwalten
und nur dann die glEnable/glDisable-Calls machen, wenn sie auch
wirklich nötig sind. Dazu muss man aber 100% sicher sein, dass die
States nicht anderswo gesetzt werden können.
Diese Variante hat den Vorteil der Verschachtelungsmöglichkeit und die
Benutzung sähe ein wenig anders/mehr aussagekräftig aus:
textmanager t;
if( usetextures )
t.enable();
else
t.disable();
Oder
t.enable(usetextures);
IMHO hätte man damit das Problem am elegantesten gelöst.
Die andere Möglichkeit mit einem enum-Flag für Enable/Disable
wäre wohl die andere gute Alternative.
MfG,
Daniel |
|
| Back to top |
|
 |
Stefan Reuther Guest
|
Posted: Fri Sep 29, 2006 8:25 pm Post subject: Re: konditionale stackobjekte |
|
|
Olaf Krzikalla wrote:
| Quote: | Hendrik Wendler wrote:
manchmal würde ich allerdings aus performancegründen
gerne auf die konstruktion eines solchen objektes
verzichten. (manche states sind teuer ...)
Dann willst Du auch nicht:
function drawtextured_quad(bool texneeded)
{
std::auto_ptr<texenabler*> p (texneeded ? new texenabler() : 0);
draw_quad();
}
|
Wenn du auf Heapallokation verzichten willst, geht auch sowas:
#include <new>
template<typename T>
class Maybe {
union { char data[sizeof(T)]; double align; } u;
T* p;
public:
Maybe() : p(0) { }
~Maybe() { if (p) p->~T(); }
void construct()
{
p = new (u.data) T();
}
template<typename A>
void construct(const A& a)
{
p = new (u.data) T(a);
}
// ggf. mehr construct-Methoden...
};
und dann
void drawtextured_quad(bool texneeded) {
Maybe<texenabler> t;
if (texneeded) t.construct();
draw_quad();
}
Das hat natürlich die üblichen Nachteile von placement-new (stimmt das
Alignment?) und Durchreichen-von-Parametern-durch-Templates (ist es
sinnvoll, einen bool per 'const bool&' zu übergeben?).
| Quote: | class empty_struct {};
class texenabler: public empty_struct { /*...*/ };
function drawtextured_quad(bool texneeded)
{
const empty_struct& e = texneeded ? texenabler() : empty_struct();
draw_quad();
}
Die Frage ist hier, ob beide temporäre Objekte im ?: Ausdruck erzeugt
werden oder nur das jeweils gebrauchte (welches dann erst wieder mit der
Referenz ablebt, wenn der Compiler sein Handwerk versteht). Ich habe
dazu keine eindeutige Aussage gefunden, lediglich 5.16.1: "Only one of
the second and third expressions is evaluated." Aber 'evaluated' ist
nicht unbedingt 'constructed'.
|
Der texenabler wird möglicherweise per slicing/Kopierkonstruktor in ein
empty_struct umgewandelt. Siehe 8.5.3p5, 2. Fall: dort gibt es die
Möglichkeiten
# The reference is bound to the object represented by the rvalue (see
# 3.10) or to a subobject within that object.
und
# A temporary of type "cv1 T2" [sic] is created, and a constructor is
# called to copy the entire rvalue object into the temporary. The
# reference is bound to the temporary or to a subobject within the
# temporary.
gcc wählt die zweite Möglichkeit. Da der Typ des '?'-Ausdrucks aber
empty_struct ist, wird eben eine Kopie des texenablers als empty_struct
erzeugt.
Stefan |
|
| Back to top |
|
 |
Marcel Müller Guest
|
Posted: Sat Sep 30, 2006 9:11 am Post subject: Re: konditionale stackobjekte |
|
|
Hallo!
Stefan Reuther schrieb:
| Quote: | void construct()
{
p = new (u.data) T();
}
|
Oder noch eine Nummer frecher, mit alloca:
void construct()
{
p = new (alloca(sizeof(T))) T();
}
Dann wird bei vielen Maybe Objekten auch nur der Speicher für die
benötigten belegt.
Selbstverständlich darf Maybe selbst dann nur noch auf dem Stack liegen..
Marcel |
|
| Back to top |
|
 |
Stefan Reuther Guest
|
Posted: Sat Sep 30, 2006 2:49 pm Post subject: Re: konditionale stackobjekte |
|
|
Marcel Müller wrote:
| Quote: | Stefan Reuther schrieb:
void construct()
{
p = new (u.data) T();
}
Oder noch eine Nummer frecher, mit alloca:
void construct()
{
p = new (alloca(sizeof(T))) T();
}
Dann wird bei vielen Maybe Objekten auch nur der Speicher für die
benötigten belegt.
|
Insbesondere wird der Speicher sofort nach dem Verlassen von 'construct'
wieder freigegeben, und das Objekt hängt ab da in der Luft.
Abgesehen davon ist 'alloca' nicht standardisiert und in den meisten
Fällen ein übler Hack, der nur unter schwammig definierten Bedingungen
überhaupt funktioniert.
p = strcpy(alloca(strlen(x)+1), x); // funktioniert oder nicht?
Stefan |
|
| Back to top |
|
 |
Markus Schaaf Guest
|
Posted: Sat Sep 30, 2006 5:10 pm Post subject: Re: konditionale stackobjekte |
|
|
"Stefan Reuther" <stefan.news (AT) arcor (DOT) de> schrieb:
| Quote: | Abgesehen davon ist 'alloca' nicht standardisiert und in den meisten
Fällen ein übler Hack, der nur unter schwammig definierten Bedingungen
überhaupt funktioniert.
p = strcpy(alloca(strlen(x)+1), x); // funktioniert oder nicht?
|
Hilfst Du mir auf die Sprünge? Ich sehe das Problem nicht. |
|
| Back to top |
|
 |
Stefan Reuther Guest
|
Posted: Sat Sep 30, 2006 7:16 pm Post subject: Re: konditionale stackobjekte |
|
|
Markus Schaaf wrote:
| Quote: | "Stefan Reuther" <stefan.news (AT) arcor (DOT) de> schrieb:
Abgesehen davon ist 'alloca' nicht standardisiert und in den meisten
Fällen ein übler Hack, der nur unter schwammig definierten Bedingungen
überhaupt funktioniert.
p = strcpy(alloca(strlen(x)+1), x); // funktioniert oder nicht?
Hilfst Du mir auf die Sprünge? Ich sehe das Problem nicht.
|
Nach Schema F übersetzt ergibt das
push x ; 2. Parameter für strcpy
push x ; Parameter für strlen
call strlen
add esp, 4 ; Parameter von strlen wegräumen
add eax, 1 ; "+1"
sub esp, eax ; das ist 'alloca(strlen(x)+1)', zum Beispiel
mov eax, esp ; aus einem Assemblermakro entstanden
push eax ; 1. Parameter für strcpy
call strcpy
add esp, 8 ; strcpy-Parameter wegräumen
mov p, eax
Ausnahme: er erkennt die 'alloca'-Funktion und weiß, dass er sämtliche
alloca-Aufrufe auswerten muss, bevor er zum Aufruf der eigentlichen
Funktion übergeht (das macht der gcc offenbar). Oder er kopiert die
bereits auf dem Stack befindlichen Parameter um (das macht der
Borland-Compiler), jedenfalls kann ich die beiden Compiler hier
zugegebenermaßen nicht spontan zu Fehlverhalten überreden (bin mir aber
relativ sicher, das mit früheren gccs bereits geschafft zu haben).
Dann gibt es noch
# Do not use `alloca' inside the arguments of a function call--you
# will get unpredictable results, because the stack space for the
# `alloca' would appear on the stack in the middle of the space for the
# function arguments. An example of what to avoid is `foo (x, alloca
# (4), y)'.
[(libc.info)Automatic Storage with Variable Size]
Dazu kommen dann noch so hübsche Restriktionen wie "eine Übersetzungs-
einheit, die alloca benutzt, muss mit '#pragma alloca' beginnen" (WIMRE
der AIX-Compiler). Und dann hat nicht jeder alloca (z.B. der freie
Turbo-C-Compiler, den ich verwende, wenn ich eine 16-bit-.exe brauche).
Außerdem ist's halt nirgends formal spezifiziert, nichtmal in der Single
Unix Specification. Würde man es formal spezifizieren, müsste man wohl
so hübsche Restriktionen einbauen wie bei setjmp, welches laut ISO
9899:1999 nichtmal auf der rechten Seite einer Zuweisung stehen darf.
Mir ist das schlicht zu viel Gefrickel auf einen Haufen, zumal ich
bisher keine Situation hatte, wo alloca wirklich notwendig gewesen wäre.
Immerhin gibt's in neuen Compilern auch VLAs, mit wesentlich besser
spezifizierter Semantik.
Stefan |
|
| Back to top |
|
 |
Christian Becker Guest
|
Posted: Sun Oct 01, 2006 7:09 pm Post subject: Re: konditionale stackobjekte |
|
|
On Thu, 28 Sep 2006 10:23:10 +0200, Hendrik Wendler wrote:
| Quote: | aus performance gründen ist es naturlich nicht
besonders gut, vor jedem zu zeichnenden punkt/linie/fläche
alle states zu setzen.
daher benutze ich gerne stackobjekte, die im
konstruktor einen state setzen und im destruktor
wieder löschen. beispiel:
|
Inwieweit bringen denn diese Stackobjekte mehr Performance?
Dein:
| Quote: | function drawtextured_quad()
{
texenabler e;
draw_quad();
}
|
ist doch nichts anderes als ein:
function drawtextured_quad()
{
glEnable(TEX2D);
draw_quad();
glDisable(TEX2D);
}
Wenn du jetzt drawtextured_quad() in einer Schleife 100 mal aufrufst, wird
doch der Texture-Modus explizit 100 mal abwechselnd angeschalten und gleich
wieder ausgeschalten.
Ich kenn mich jetzt auch nicht so gut aus, aber was wäre mit einem
Statemanager der sich merkt in welchem Modus gerade gezeichnet wird? Der
also kein glEnable(TEX2D) mehr macht wenn man bereits im TEX2D Modus ist.
Und auch ein glDisable(TEX2D) erst dann wenn es wirklich nötig ist.
mfg
Christian Becker |
|
| 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
|
|