/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
jdjespers.. 500
kyllekylle 500
Bech_bb 500
scootergr.. 300
gibson 300
molokyle 287
10  strarup 270
streams vs. overload af +
Fra : Rasmus Kaae


Dato : 03-06-02 07:14

Hejsa,

igår sad vi to personer og diskuterede omkring hvad der var bedst at bruge,
enten streams eller overload af '+' operatoren.
Vi havde følgende to kodestumper:

stream << a << b << c;

og

stream+=a+b+c;

Hvor jeg personligt mener, at streams er at foretrække, da det er let at
gennemskue hvad der foregår, mente den anden programmør at +=/+
konstruktionen var pænere at se på i koden.

Mit modeksempel på at +=/+ konstruktionen var grim er som følger:

stream << 1 << 2 << 3; => medfører at tallene bliver lagt i [1,2,3]
rækkefølge
stream+=1+2+3; => da compileren vil behandle højresiden før venstre-siden
vil konstruktionen her resultere i at parameteren til stream+= er summen,
altså 4, hvilket ikke var det tilsigtede.


Hvad mener i?



 
 
Claus Rasmussen (03-06-2002)
Kommentar
Fra : Claus Rasmussen


Dato : 03-06-02 08:36

Rasmus Kaae wrote:

> igår sad vi to personer og diskuterede omkring hvad der var bedst at
> bruge, enten streams eller overload af '+' operatoren.
> Vi havde følgende to kodestumper:
>
> stream << a << b << c;
>
> og
>
> stream+=a+b+c;
>
> Hvor jeg personligt mener, at streams er at foretrække, da det er let at
> gennemskue hvad der foregår, mente den anden programmør at +=/+
> konstruktionen var pænere at se på i koden.

Det er jo en smagssag. Når du arbejder med strenge bruger du jo '+'
operatoren:

streng += "Hej" + "med" + "dig";


> Mit modeksempel på at +=/+ konstruktionen var grim er som følger:

Du leverer ikke noget modeksempel, der skulle gøre +=/+ "grimme". Du
leverer i stedet et eksempel på, hvorfor +=/+ slet ikke kan bruges,
når man arbejder på streams.


> stream << 1 << 2 << 3; => medfører at tallene bliver lagt i [1,2,3]
> rækkefølge
> stream+=1+2+3; => da compileren vil behandle højresiden før venstre-siden
> vil konstruktionen her resultere i at parameteren til stream+= er summen,
> altså 4, hvilket ikke var det tilsigtede.
>
> Hvad mener i?

Jeg mener, at resultatet vil være 6, men ellers har du helt ret

-Claus



Mogens Hansen (03-06-2002)
Kommentar
Fra : Mogens Hansen


Dato : 03-06-02 19:20


"Claus Rasmussen" <clr@cc-consult.dk> wrote

[snip]
> streng += "Hej" + "med" + "dig";

Det svarer til
(streng += (("Hej" + "med") + "dig"));

hvor der 2 gange vil blive lagt "char*" sammen, hvilket man ikke kan.
Der mangler lidt typeinformation, for at få det til at virke. F.eks.
streng += string("Hej") + "med" + "dig";

Venlig hilsen

Mogens Hansen



Daniel Kjøller Skove~ (03-06-2002)
Kommentar
Fra : Daniel Kjøller Skove~


Dato : 03-06-02 16:11

Hvis det er meningen, at tallene 1, 2 og 3 skal lægges ind efter hinanden
virker det mest logisk med bitshiftoperatoren (det, du kalder stream). Først
lægger vi 1 ind, så 2 og så 3.
Og plusserne:
Når den behandler højresiden først (bruger integer plusoperatoren), kan der
så nogen diskussion om, hvad man skal bruge?




Mogens Hansen (03-06-2002)
Kommentar
Fra : Mogens Hansen


Dato : 03-06-02 19:28


"Rasmus Kaae" <macaw@WHATEVERMAKESYOUHAPPYhotmail.com> wrote

[snip]
> Vi havde følgende to kodestumper:
>
> stream << a << b << c;
>
> og
>
> stream+=a+b+c;
>

[snip]
> ... da compileren vil behandle højresiden før venstre-siden
> vil konstruktionen her resultere i at parameteren til stream+= er summen,
> altså 4, hvilket ikke var det tilsigtede.
>


Forskellen er at assignment operatorer (=, +=, etc.) grupperer fra højre til
venstre, og skifte operatorer (<<, >>) grupperer fra venstre til højre.

Det vil sige at
stream << a << b << c;
er det samme som
(((stream << a) << b) << c);
som jo igen er det samme som
((stream.operator<<(a)).operator<<(b)).operator(c);

og
stream+=a+b+c;
er det samme som
(stream += ((a+b)+c));

Typen af "stream" indgår med skifte operatorerne i det første der bliver
evalueret - det er det der får det til at virke.
Typen af "stream" indgår med assignment operator i det sidste der bliver
evalueret, og derfor virker det ikke.

Hvis assignment operator skulle kunne bruges, ville det kræve noget i
retningen af
stream += streamer(a) + b + c;
hvor der bliver oprettet et temporært objekt.
Det ser ikke just pænt ud, udover at det nemt vil kunne give et performance
overhead.

Overvejelserne om hvorvidt der skulle bruges en overloaded funktion eller
overloadede operatorer, og hvilken overloaded operator, står beskrevet i
The Design and Evolution of C++
Bjarne Stroustrup
ISBN 0-201-54330-3
(ofte kaldet D&E) side 186-187

Venlig hilsen

Mogens Hansen



Bjarke Dahl Ebert (03-06-2002)
Kommentar
Fra : Bjarke Dahl Ebert


Dato : 03-06-02 22:53

"Rasmus Kaae" <macaw@WHATEVERMAKESYOUHAPPYhotmail.com> wrote in message
news:adf1fc$gcs$1@news.net.uni-c.dk...

> Mit modeksempel på at +=/+ konstruktionen var grim er som følger:
>
> stream << 1 << 2 << 3; => medfører at tallene bliver lagt i [1,2,3]
> rækkefølge
> stream+=1+2+3; => da compileren vil behandle højresiden før venstre-siden

Da der allerede er flere relevante svar i gruppen (fx at sidstnævnte
"mulighed" slet ikke er en mulighed), vil jeg blot tilføje:

Metoden med at overloade venstre-shift operatoren har også sine problemer.
Fx.:

stream << 1+2 << 3+4;

Gad vide om ikke det grupperer som:

(stream << 1) + (2<<3) + 4;

?

Jeg kan faktisk ikke huske precendens-rækkefølgen, men alene det er vel et
problem - så er der garanteret mange andre der ikke kan.

Min egen anti-C++-farvede holdning er at metoden med at bruge "<<" er at
grimt hack. Man forsøger næsten at putte en ny konstruktion ind i sproget
(man må indrømme at

cout << "Hello: " << i << ", " << j << endl;

ser ud som om sproget har en form for print-statement), men dog uden at
ændre sproget, kun standard-biblioteket. Derved opnår man selvfølgelig den
store ulempe at compileren stadig blot ser '<<' som bitvis venstre-shift,
som dog kan overloades. Overload eller ej, så har den stadig præcedens som
om det er bit-shift.
En anden åbenlys ulempe er efter min mening at en overloadet '<<' pinedød
skal returnere "stream". Hvis den ikke gør det, opnår man en højst
besynderlig situation hvor "cout << foo << bar;" ikke er det samme som "cout
<< foo; cout << bar;".

Bjarke





Mogens Hansen (04-06-2002)
Kommentar
Fra : Mogens Hansen


Dato : 04-06-02 06:25


"Bjarke Dahl Ebert" <bebert@worldonline.dk> wrote

[snip]
> stream << 1+2 << 3+4;
>
> Gad vide om ikke det grupperer som:
>
> (stream << 1) + (2<<3) + 4;
>
> ?
>

Hvorfor gætte ?
2 bedre løsninger er:
* sæt parenteser. Hvis du er i tvivl, er den der senere skal læse det
måske også i tvivl
* undersøg det. Læs det i en bog, i C++ Standarden eller skriv et program
der viser opførslen.

Og nej, det bliver ikke hvad du foreslog, men
stream << (1+2) << (3+4);
hvilket ikke er overranskende

> Jeg kan faktisk ikke huske precendens-rækkefølgen, men alene det er vel et
> problem - så er der garanteret mange andre der ikke kan.
>

Det kan jeg heller ikke altid. Normalt opfører det sig som jeg forventer.
Sæt parenteser der hvor du er i tvivl.

> Min egen anti-C++-farvede holdning er at metoden med at bruge "<<" er at
> grimt hack. Man forsøger næsten at putte en ny konstruktion ind i sproget
> (man må indrømme at
>
> cout << "Hello: " << i << ", " << j << endl;
>
> ser ud som om sproget har en form for print-statement), men dog uden at
> ændre sproget, kun standard-biblioteket.

Sådan kan man se så forskelligt på det.
For mig er det en af de fundament sunde tanker i C++, at lægge så meget
funktionalitet i biblioteker, og at dem der skriver Standard Library ikke
har adgang til særlige egenskaber. Alle kan skrive biblioteker
* som passer til et givent domæne
* som ligner sprogudvidelser, hvis det er passende
* kan have samme performance som indbygget funktionalitet
Jeg skal nok uddybe det synspunkt lidt senere - jeg har ikke mere tid lige
nu.

> Derved opnår man selvfølgelig den
> store ulempe at compileren stadig blot ser '<<' som bitvis venstre-shift,
> som dog kan overloades. Overload eller ej, så har den stadig præcedens som
> om det er bit-shift.

Hvad er det præcist ulempen er for almindelige programmører ?

> En anden åbenlys ulempe er efter min mening at en overloadet '<<' pinedød
> skal returnere "stream". Hvis den ikke gør det, opnår man en højst
> besynderlig situation hvor "cout << foo << bar;" ikke er det samme som
"cout
> << foo; cout << bar;".
>

Hvilken type returnerer cout << foo ?
Givetvis noget, hvor << bar ikke giver mening - altså en compilerfejl.
Og ja, man skal kende et sprogs idiomer for at kunne bruge det effektivt.

Venlig hilsen

Mogens Hansen



Mogens Hansen (04-06-2002)
Kommentar
Fra : Mogens Hansen


Dato : 04-06-02 16:24


"Mogens Hansen" <mogens_h@dk-online.dk> wrote

> "Bjarke Dahl Ebert" <bebert@worldonline.dk> wrote
>
[snip]
> > Min egen anti-C++-farvede holdning er at metoden med at bruge "<<" er at
> > grimt hack. Man forsøger næsten at putte en ny konstruktion ind i
sproget
> > (man må indrømme at
> >
> > cout << "Hello: " << i << ", " << j << endl;
> >
> > ser ud som om sproget har en form for print-statement), men dog uden at
> > ændre sproget, kun standard-biblioteket.
>
> Sådan kan man se så forskelligt på det.
> For mig er det en af de fundament sunde tanker i C++, at lægge så meget
> funktionalitet i biblioteker, og at dem der skriver Standard Library ikke
> har adgang til særlige egenskaber. Alle kan skrive biblioteker
> * som passer til et givent domæne
> * som ligner sprogudvidelser, hvis det er passende
> * kan have samme performance som indbygget funktionalitet
> Jeg skal nok uddybe det synspunkt lidt senere - jeg har ikke mere tid lige
> nu.
>

Jeg syntes udsagnet "Biblioteks design _er_ sprog design" er vældigt
fornuftigt.

Jeg anser det for at være en stor styrke at man ikke behøves at være
compiler konstruktør, og man ikke behøves at få godkendelse fra ISO C++
standard komiteen, for at kunne tilføje nyttige abstraktioner, som opfører
sig lige så godt som hvis de var bygget direkte ind i sproget.
Det er nyttigt fordi det giver mig som programmør stor frihed til at vælge
og eksperimentere, og dermed opbygge erfaring.
Det er nyttigt fordi der findes mange flere dygtige folk, der har nyttige
ideer, end der findes compiler konstruktører. Derfor giver designet i C++
alle disse dygtige folk mulighed for at ytre sig.
Det er nyttigt fordi bibliotekerne, hvis de baserer sig på ISO C++, typisk
umiddelbart vil være tilgængelige for et bredt publikum.

For mig aftvinger det dyb respekt, at de utvivlsomt meget dygtige folk, der
har været involveret i designet af C++, har erkendt at de ikke ved hvad der
er bedst for alle mennesker, og derfor har lagt meget vægt på at løse
generelle problemer og derved understøtte muligheden for at lave nye
konstruktioner, som de ikke havde tænkt på.

Prøv at se det konkrete eksempel, streaming.
Det er ikke forbeholdt nogen, at definere et lukket set af typer som kan
streames. Jeg kan til enhver tid definere "my_class" og definere hvordan den
skal skrives ud, på en effektiv og typesikker måde. Det er fundamentalt
anderledes end "printf" i C.

Der er mange eksempler på biblioteker, der nærmest putter nye konstruktioner
ind i sproget, til stor glæde mange.

Hvis ikke C++ havde været designet på den måde havde STL ikke eksisteret.
Så vidt jeg har forstået, valgte Alex Stephanov (hoved designeren af STL)
ikke C++ til at implementere STL fordi han var dybt involveret i C++.
Han havde først prøvet at implementere det i Ada, men kunne ikke. Alex
Stephanov var dybt involveret i generisk programmering, og C++'s template
mekanisme var et redskab der var tilstrækkeligt til at udtrykke det han
ønskede.

Andre _eksempler_ på biblioteker, der nærmest putter nye konstruktioner ind
i sproget er
* BLL - Lambda biblioteket i Boost
(http://www.boost.org/libs/lambda/doc/index.html).
* Spririt - et parser bibliotek (http://spirit.sourceforge.net/)
* MTL - et matrix template library
(http://www.osl.iu.edu/research/mtl/intro.php3)


BLL gør det muligt at skrive, sådan noget som
for_each(a.begin(), a.end(), std::cout << _1 << ' ');


Spirit gør det muligt nærmest at skrive EBNF (Extended Backus Normal Form) i
ren C++, når man beskriver en parser.
F.eks. er

rule<> expr;
rule<> integer = lexeme[ (!(ch_p('+') | '-') >> +digit)[&doInt] ];
rule<> group = '(' >> expr >> ')';
rule<> expr1 = integer | group;
rule<> expr2 = expr1 >> *(('*' >> expr1)[&doMult] | ('/' >>
expr1)[&doDiv]);
expr = expr2 >> *(('+' >> expr2)[&doAdd] | ('-' >> expr2)[&doSubt]);

en komplet beskrivelse af en parser til regnestykker som f.eks. "1 + ((6 *
200) - 20) / 6".
"doInt", "doAdd", "doMult" og "doDiv" er simple funktioner, der behandler de
enkelte del udtryk:
void doInt(char const* str, char const* end)
{
string s(str, end);
cout << s << endl;
}

void doAdd(char const*, char const*) { cout << "ADD\n"; }
void doSubt(char const*, char const*) { cout << "SUBT\n"; }
void doMult(char const*, char const*) { cout << "MULT\n"; }
void doDiv(char const*, char const*) { cout << "DIV\n"; }

Konsekvensen af at vælge at lægge meget funktionalitet i biblioteker i
stedet for direkte i sproget (core language), gør det muligt at understøtte
mange flere specielle domainer (f.eks. parsere, matricer), på måder der er
naturlige for domainet.

Venlig hilsen

Mogens Hansen



Benny Andersen (04-06-2002)
Kommentar
Fra : Benny Andersen


Dato : 04-06-02 20:40

On Mon, 3 Jun 2002 23:52:41 +0200, Bjarke Dahl Ebert <bebert@worldonline.dk>
wrote:

[klip]
> Min egen anti-C++-farvede holdning er at metoden med at bruge "<<" er at
> grimt hack. Man forsøger næsten at putte en ny konstruktion ind i sproget
> (man må indrømme at
>
> cout << "Hello: " << i << ", " << j << endl;
>
> ser ud som om sproget har en form for print-statement), men dog uden at
> ændre sproget, kun standard-biblioteket. ...

Jeg kan også huske forbavselsen, første gang jeg så 'venstre skift' anvendt
således.

Er sagen ikke, at man hurtigt vænnes til at opfatte I/O, som det eneste
væsentlige for udtryk som

cout << identifier;

eller

int printf(const char *format, ...);

men i sprog-syntakstisk forstand, er det en expression og et funktionskald,
hvis side efekter er udskrivning til stdout. C++ har igen statements til I/O.
Nu er genbruget af et begrænset antal operatorer og visse keywords et af
c/c++ finurlige kendetegn.

Jeg synes dog også at der er en forståelsesmæssig spændvide mellem, ... de
grafiske letforståelige 'strømpile', som både separerer de elementer som skal
ud, i læseretningen, op peger på den 'cout', som man næsten opfatter som output
konsolen; ... og de på hinanden følgende kald til cout objektet.

Det er som om

cout << identifier;

gør fyldest gennem to niveauer af sideefekter(ud over udskrift). Først muliggør
operator overloadning, at objektet på venstre side af operatoren modificeres.
Den efekt som oprindeligt alene '=' havde, og i statement typen assignment
eller initialisation, optræder nu i expressions. Dernæst anvendes den endelige
returværdi ikke, og 'mellem' returværdier anvendes til at udløse på hinanden
følgende kald.

int a;
34+6; //eksempler på expressions,
a; //som hverken indgår i assignment eller initialisation.

Så '<<' er skutte en strømpil, men funktionalitet,
og det kan man godt blive lidt skitzofren af at se på.

Sjovt som sproget er en delmængde af det syntaktiske korrekte.

#include <cstdlib>

class C
{
int v;
public:
C(int vv) : v(vv) {}
operator bool() { return v; }
};

bool retbool(void (*pf)(int), int v, bool b=false)
{
pf(v);
return b;
}

void foo()
{
C c(1);
c || retbool(exit,1);
// er jeg en slem dreng?
}


-- Benny
   Som lige har slugt en perle.

Søg
Reklame
Statistik
Spørgsmål : 177558
Tips : 31968
Nyheder : 719565
Indlæg : 6408925
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste