/ 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
Kopiering af klasse
Fra : SuneF


Dato : 16-04-01 16:00

Okay, det er vel et C++ spm. men jeg stiller det alligevel.

Jeg har omskrevet et program til at bruge lidt klasser.
Programmet virker som det skal, men det kører ca. en faktor 10-100 gange
langsommere end før jeg indførte klasserne.

Jeg har fx.

class Data{
public:
double x[20][20];
};

Data mydata[100];
void Energy(Data &dat);

Det kører nogenlunde, men hvis jeg så ændrer til fx.

class Data{
public:
double x[200][200];
}

så bliver det næsten 100 gange langsommere.
Udregnerne der sker er de samme, det er rent spild og burde intet betyde.
Det eneste jeg kan forklare det med er, at hele klassen kopieres imellem
funktionerne.

Jeg har prøvet at omskrive det hele med pointere:
void Energy(Data *dat);

men det giver det samme.

Inden jeg brugte klasserne kørte jeg bare med x[][] som global variabel, men
nu har jeg brug for flere instances.

Er der noget jeg har misset, burde det ikke virke (jeg er rimelig newbie
indenfor det klasse halløj)?


-Sune




 
 
Lau Sennels (16-04-2001)
Kommentar
Fra : Lau Sennels


Dato : 16-04-01 16:45

SuneF wrote:
>
> Okay, det er vel et C++ spm. men jeg stiller det alligevel.

Det er så i orden. C++ er trods alt on-topic i gruppen.

> Jeg har fx.

1)

> class Data{
> public:
> double x[20][20];
> };


> Data mydata[100];
> void Energy(Data &dat);

Energy er ikke et medlem af Data?
Husk på at en af de centrale designkarakteristika
ved OOP, er at klasser indkapsler både data og tilhørende
funktioner.

>
> Det kører nogenlunde, men hvis jeg så ændrer til fx.

2)

> class Data{
> public:
> double x[200][200];
> }
>
> så bliver det næsten 100 gange langsommere.

Det synes jeg egentlig ikke er sært.
Du definerer mydata som et array af 100 objekter af typen
Data.
I 1) svarer det til at der reserveres hukommelse til 100,
20*20 = 400 double "elementer".
I 2) svarer det til at der reserveres hukommelse til 100,
200*200 = 40000 double "elementer".
Der er netop en faktor 100 til forskel. Uanset hvordan du
refererer til variable i som parametre i dine funktioner
skal programmet stadig håndtere 100 gange så store variable.

> Er der noget jeg har misset, burde det ikke virke (jeg er rimelig newbie
> indenfor det klasse halløj)?

Det kan godt være du skulle finde en mere effektiv måde at
indkapsle dine data/funktioner. Lidt information om programmets
funktion, og lidt mere komplet kode ville hjælpe. En anden ting
er at std::vector<T>, nok er en væsentlig bedre container end en
to-dimensionel array. Især med så store variable.

--
Mvh
Lau Sennels

Mogens Hansen (16-04-2001)
Kommentar
Fra : Mogens Hansen


Dato : 16-04-01 18:28

Hej Lau,
"Lau Sennels" <"sennels"@\"SpAM\"gjk.dk> wrote in message

> Det kan godt være du skulle finde en mere effektiv måde at
> indkapsle dine data/funktioner. Lidt information om programmets
> funktion, og lidt mere komplet kode ville hjælpe. En anden ting
> er at std::vector<T>, nok er en væsentlig bedre container end en
> to-dimensionel array. Især med så store variable.

Hvorfor er std::vector<T> bedre, hvis størrelsen på datastrukturen er
compile-time statisk ?

Venlig hilsen

Mogens Hansen



Lau Sennels (16-04-2001)
Kommentar
Fra : Lau Sennels


Dato : 16-04-01 19:19

Mogens Hansen wrote:
>
> Hej Lau,

Hej Mogens

> Hvorfor er std::vector<T> bedre, hvis størrelsen på datastrukturen er
> compile-time statisk ?

Dels fordi det ikke står klart for mig om Sune har brug for matricer
med /netop/ 200*200 elementer, eller om dimensionerne er valgt for at
have plads nok. Det er også mit indtryk at STL-implementionen af
vector-klassen laver en "sikrere" allokering end et low-level array.
Dels fordi iteratorr, automatisk intialisering og genersike algoritmer
gør det noget sikrere (og nemmere) at manipulere så store datamængder.

--
Mvh
Lau Sennels

Mogens Hansen (16-04-2001)
Kommentar
Fra : Mogens Hansen


Dato : 16-04-01 20:05

Hej Lau,
"Lau Sennels" <"sennels"@\"SpAM\"gjk.dk> wrote in message
news:newscache$pjdwbg$syk$1@kalvebod.groenjord.dk...
> Mogens Hansen wrote:
> >
> > Hej Lau,
>
> Hej Mogens
>
> > Hvorfor er std::vector<T> bedre, hvis størrelsen på datastrukturen er
> > compile-time statisk ?
>
> Dels fordi det ikke står klart for mig om Sune har brug for matricer
> med /netop/ 200*200 elementer, eller om dimensionerne er valgt for at

Det står heller ikke klart for mig.
Hvis det er ikke _netop_ er 200*200, så er jeg enig i at vector er et godt
bud.

> have plads nok. Det er også mit indtryk at STL-implementionen af
> vector-klassen laver en "sikrere" allokering end et low-level array.

Når arrayet har en statisk størrelse, og er datamedlem i en klasse - i
modsætning til allokeret på heapen, hvor man måske også skal holde styr på
hvor stort det er for tiden - så er det ikke sikrere at benytte vector.
Der er f.eks. ikke check på om man tilgår vector'en ud over slutningen, når
man bruger "operator[]" (som man typisk gør), men kun når man bruger "at".

> Dels fordi iteratorr, automatisk intialisering og genersike algoritmer
> gør det noget sikrere (og nemmere) at manipulere så store datamængder.

Det er det samme, bortset fra den automatiske initialisering - som
constructoren til Data kunne gøre.
Alle de generiske algoritmer fungerer lige så godt med array som med vector,
fordi at en pointer ind i arrayet er en random access iterator.

F.eks.:
vector<double> dv(10);
double da[10];
double* const da_end = da+sizeof(da)/sizeof(da[0]);

for_each(dv.begin(), dv.end(), do_something_clever());
for_each(da, da_end, do_something_clever());


Venlig hilsen

Mogens Hansen







SuneF (16-04-2001)
Kommentar
Fra : SuneF


Dato : 16-04-01 20:00

> > Data mydata[100];
> > void Energy(Data &dat);
>
> Energy er ikke et medlem af Data?
> Husk på at en af de centrale designkarakteristika
> ved OOP, er at klasser indkapsler både data og tilhørende
> funktioner.

Næhh spiller det nogen rolle, jeg har egentlig ikke brug for det?

> Der er netop en faktor 100 til forskel. Uanset hvordan du
> refererer til variable i som parametre i dine funktioner
> skal programmet stadig håndtere 100 gange så store variable.

Jeg tror jeg må lede med lys og lygte efter et sted hvor der sker en
kopiering, for jeg bruger ikke "resten" af variablen

> Det kan godt være du skulle finde en mere effektiv måde at
> indkapsle dine data/funktioner. Lidt information om programmets
> funktion, og lidt mere komplet kode ville hjælpe.

En komplet kode ville nok ikke gøre det klarere, jeg er ved at lave
simuleret udglødning på et neuralt netværk, og jeg har brug for en hel
mængde af disse netværks til at køre et større ensemble.
Bund og grund er at jeg skal have et array af structs/class'es som kan
repræsentere mit netværk.

En anden ting
> er at std::vector<T>, nok er en væsentlig bedre container end en
> to-dimensionel array. Især med så store variable.

Hmm, hurtigere end arrays?



Torsten Iversen (16-04-2001)
Kommentar
Fra : Torsten Iversen


Dato : 16-04-01 22:56


In article <9bffhk$igk$1@news.cybercity.dk>, SuneF wrote:
>En anden ting
>> er at std::vector<T>, nok er en væsentlig bedre container end en
>> to-dimensionel array. Især med så store variable.
>
>Hmm, hurtigere end arrays?
>
>

Næppe. På stort set enhver fornuftig arkitektur/implementation, jeg kan
forestille mig, må statisk allokerede arrays være hurtigst. De kan lægges
i sammenhængende hukommelse i datasegmentet, hvilket giver god ydelse på
de fleste arkitekturer og er let at optimere for compileren.

Eftersom vector tilbyder dynamisk udvidelse, må den nødvendigvis kunne
ligge på andre addresser end hvor den bliver placeret ved definition.
Derfor må der skulle en form for indirektion til i alle tilgange til
elementerne, hvilket typisk koster performance. Forskellen er dog sikkert
på en typisk platform forsvindende lille ved sekventiel adgang, da man
blot skal loade addressen ind i et register fra starten og tilgå
hukommelsen derfra i efterfølgende operationer. I et multitrådet system
bliver det mere speget.

Det kan sikkert give bedre ydelse, at ofre noget hukommelse på at bruge
en 2^n længde for den ene dimension af arrays, da addresseberegninger så
kan udføres med shift operationer i stedet for multiplikationer. Hvis din
compiler ikke kan finde ud af at optimere det, kan du evt bruge et
1-dimensionelt array og selv indsætte shift operationer i koden til at
tilgå det i 2 dimensioner.

Mht. C++ kontra C, burde compileren så vidt jeg kan se kunne optimere
begge dele lige godt, sålænge du ikke bruger virtual metoder (har jeg ret
eller hvad??).

Torsten

Mogens Hansen (17-04-2001)
Kommentar
Fra : Mogens Hansen


Dato : 17-04-01 07:51

Hej Torsten,
"Torsten Iversen" <torsten@mega.cs.auc.dk> wrote in message
news:slrn9dmqk0.s6b.torsten@mega.cs.auc.dk...
>
> forestille mig, må statisk allokerede arrays være hurtigst. De kan lægges
> i sammenhængende hukommelse i datasegmentet, hvilket giver god ydelse på
> de fleste arkitekturer og er let at optimere for compileren.

Den hukommelse som "std::vector<T>" allokerer er også een sammenhængende
blok.
Alle typiske implementeringer har altid gjort det. Det har altid været
tanken, selvom det ikke står i den oprindelige C++ Standard. Der er lavet en
opdatering af C++ Standarden, hvor det er blevet beskrevet.

>
> Eftersom vector tilbyder dynamisk udvidelse, må den nødvendigvis kunne
> ligge på andre addresser end hvor den bliver placeret ved definition.
> Derfor må der skulle en form for indirektion til i alle tilgange til
> elementerne, hvilket typisk koster performance. Forskellen er dog sikkert
> på en typisk platform forsvindende lille ved sekventiel adgang, da man

Netop.

>
> Mht. C++ kontra C, burde compileren så vidt jeg kan se kunne optimere
> begge dele lige godt, sålænge du ikke bruger virtual metoder (har jeg ret
> eller hvad??).

Ja, du har stort set ret.
Exception håndtering i C++ påtrykker typisk et lille overhead, selv om man
ikke bruger det.
Det kan implementeres i compileren så det ikke giver noget run-time
overhead, hvis der ikke bliver smidt exceptions, men det er ikke
almindeligt.
Exception håndtering, kan på mange compilere slås fra som en
compiler-option/sprog-udvidelse.
Hvis man har brug for virtual metoder (run-time polymophy) kan man typisk
ikke gøre det hurtigere i C end i C++.

Venlig hilsen

Mogens Hansen



Mogens Hansen (16-04-2001)
Kommentar
Fra : Mogens Hansen


Dato : 16-04-01 18:28

Hej Sune,
"SuneF" <noluck@nowhere.dk> wrote in message
news:9bf1ek$2ues$1@news.cybercity.dk...

> class Data{
> public:
> double x[20][20];
> };
>
> Data mydata[100];

Det er rigtigt at du vil have 100*20*20 doubles = 40000 doubles ?

> void Energy(Data &dat);

Det skulle være udemærket . Evt. kan det måske være
void Energy(const Data &dat);
hvis "Energy" ikke ændrer "dat".

>
> Det kører nogenlunde, men hvis jeg så ændrer til fx.

Hvad betyder "nogenlunde" ?
Lige så hurtigt? 5 gange langsommere ?

>
> class Data{
> public:
> double x[200][200];
> }
>
> så bliver det næsten 100 gange langsommere.

Da har 100 gange så meget data

> Udregnerne der sker er de samme, det er rent spild og burde intet betyde.
> Det eneste jeg kan forklare det med er, at hele klassen kopieres imellem
> funktionerne.

Hvis du er i tvivl om der laves kopier af hele klassen, så er her et par
tricks:
* Erklær copy-constructor og copy-assignment private
og undlad at implementere dem.
Så vil enten compileren eller linkere brokke sig, hvis
der er brug for dem.
* Erklær og implementer copy-constructor
og copy-assignment, og se hvorfra de bliver kaldt.
Så kan du vurdere om det er tilsigtet.

f.eks.:
class Data
{
public:
Data(void) {}
double x[20][20];

private:
Data(const Data&); // copy-constructor
Data& operator=(const Data&); // copy-assignment
};

Husk at når du laver een constructor (f.eks. copy-constructoren) så laver
compileren nogen default constructor.


>
> Jeg har prøvet at omskrive det hele med pointere:
> void Energy(Data *dat);
>
> men det giver det samme.


Der er det samme at bruge pointer som at bruge reference, borset af at en
pointer kan være null og kan sættes til at pege på et andet objekt.
En reference _skal_ referere til et gyldigt objekt, og vil _altid_ referere
til det samme objekt.

>
> Inden jeg brugte klasserne kørte jeg bare med x[][] som global variabel,
men
> nu har jeg brug for flere instances.
>
> Er der noget jeg har misset, burde det ikke virke (jeg er rimelig newbie
> indenfor det klasse halløj)?

Det skal kunne køre med samme hastighed, bortset fra et lille overhead fra
at skelne mellem hvilken af de mange instancer du bruger.

Jeg syntes ikke, at det du har posted nu afslører hvorfor det kører
langsommere.

Venlig hilsen

Mogens Hansen




Lau Sennels (16-04-2001)
Kommentar
Fra : Lau Sennels


Dato : 16-04-01 19:37

Mogens Hansen wrote:
>
> Hej Sune,
> "SuneF" <noluck@nowhere.dk> wrote in message
> news:9bf1ek$2ues$1@news.cybercity.dk...


> > void Energy(Data &dat);
>
> Det skulle være udemærket . Evt. kan det måske være
> void Energy(const Data &dat);
> hvis "Energy" ikke ændrer "dat".

Er der ikke en ydelsesfordel forbundet med at
lade en medlemsfunktion behandle klassedata,
hvis den er deklareret inline? Man må formode
at Energy skal kaldes mindst en gang for alle
(ikke-tomme) elementer i mydata.

--
Mvh
Lau Sennels

Mogens Hansen (16-04-2001)
Kommentar
Fra : Mogens Hansen


Dato : 16-04-01 20:12

Hej Lau,
"Lau Sennels" <"sennels"@\"SpAM\"gjk.dk> wrote in message
news:newscache$teewbg$hml$1@kalvebod.groenjord.dk...
> Mogens Hansen wrote:
> >
> > Hej Sune,
> > "SuneF" <noluck@nowhere.dk> wrote in message
> > news:9bf1ek$2ues$1@news.cybercity.dk...
>
>
> > > void Energy(Data &dat);
> >
> > Det skulle være udemærket . Evt. kan det måske være
> > void Energy(const Data &dat);
> > hvis "Energy" ikke ændrer "dat".
>
> Er der ikke en ydelsesfordel forbundet med at
> lade en medlemsfunktion behandle klassedata,
> hvis den er deklareret inline? Man må formode

Nej.
Energy kan tilsvarende erklæres inline. Jeg kan iøvrigt nemt forestille mig
at overheaded ved at kalde en funktion, er meget lille i forhold til at
behandling 200*200 double's.

Hvis Energy ikke er member funktion, bliver den til
void Energy(const Data& dat)
{
// ...
do_something_clever(dat.x[i][j]);
// ...
}

og hvis den er en member funktion, bliver den til
void Data::Energy(void) const
{
// ...
do_something_clever(x[i][j]);
// ...
}

som reelt af compileren bliver oversat til
void Data__Energy(const Data* this) const
{
// ...
do_something_clever(this->x[i][j]);
// ...
}

Du har den samme indirektion (og dermed performance karakteristik),
hvadenten man skal skrive "dat.x[i][j]" eller "this->x[i][j]", hvis
compileren er blot tilnærmelsesvis fornuftig.

Begge varianter af Energy kan iøvrigt lige let have pointere direkte ind i
data, og incrementere pointerne uden den ekstra indirektion.

Det er ikke fordi jeg er uenig med dig i at man skal overveje om det ikke er
en fornuft design-beslutning at gøre "Energy" til en member funktion.
Det er blot at det spiller ikke nogen betydning for performance (læg i
øvrigt mærke til at praktisk taget alle algoritmer i C++ Standard library
_ikke_ er member funktioner).

> at Energy skal kaldes mindst en gang for alle
> (ikke-tomme) elementer i mydata.

Ikke forstået - måske jvf. ovenstående.

Venlig hilsen

Mogens Hansen










Søg
Reklame
Statistik
Spørgsmål : 177552
Tips : 31968
Nyheder : 719565
Indlæg : 6408849
Brugere : 218887

Månedens bedste
Årets bedste
Sidste års bedste