[C++] Input mismatch, werkt toch?

Pagina: 1
Acties:

  • maleadt
  • Registratie: Januari 2006
  • Laatst online: 05-11 22:08
Bij gebrek aan "Programming kroeg" gooi ik dit kleine vraagje maar in een apart topic O-)

Vraag in het kort:
Is het zo dat als het object dat een functie/constructor nodig heeft, niet overeen komt met het gegeven object, C++ zelf het benodigde object genereert door de constructor ervan te callen met het gegeven maar mismatching object?

Als mijn vraag niet duidelijk is: hier een aanvullend verhaaltje :*)

Ik ben al een tijdje als ontspanning bezig aan een genetisch algoritme, een vingeroefening om wat beter object-georiënteerd leren te programmeren (C++ is relatief nieuw voor mij).
Mijn programma bestaat uit een "creature", dat volgens zijn "dna" code rondkruipt in een "world". Dit heb ik dan heel gestructureerd opgebouwd, met volgende hiërarchie: world->creature->dna->gen. Elke klasse heeft zijn specifieke functies, en roept zo goed het kan enkel functies aan van de parent en child class.

Anyway, de constructor van mijn Creature klasse ziet er als volgt uit (pseudo-code):
C++:
1
2
3
4
5
6
7
Creature::Creature()
{
}
Creature::Creature(DNA inputDNA, int aantal_stapjes)
{
doe iets met inputDNA en aantal_stapjes;
}

Ik heb dus maar 2 constructors, de ene dient ervoor zodat ik later manueel de DNA en aantal stapjes nog instel, de andere om dat in 1 beweging te doen.

De constructor van mijn DNA klasse is eenvoudiger, die heeft enkel een string als input nodig.

Nu had ik in mijn main.cpp een fout gemaakt, en een creature geinitialiseerd met Creature(string, int). Fout dus, maar de compiler klaagde helemaal niet? Beter zelf, mijn programma werkte helemaal naar behoren!?
De string die ik "Creature" gaf, kwam wel overeen met de string die ik zou moeten gebruikt hebben om "DNA" te initialiseren... Is het dus zo dat als het object dat een functie/constructor nodig heeft, niet overeen komt met het gegeven object, C++ zelf het benodigde object genereert door de constructor ervan te callen met het gegeven maar mismatching object?


Alvast bedankt!
maleadt

  • user109731
  • Registratie: Maart 2004
  • Niet online
MALEADt schreef op zaterdag 31 mei 2008 @ 18:51:
Is het dus zo dat als het object dat een functie/constructor nodig heeft, niet overeen komt met het gegeven object, C++ zelf het benodigde object genereert door de constructor ervan te callen met het gegeven maar mismatching object?
Ja, de constructor van DNA word impliciet aangeroepen. Zie ook de uitleg over implicit conversion in dit artikel. Dit kun je voorkomen door de constructor te declareren als explicit.

Dus het volgende:
C++:
1
2
string s;
DNA dna = s;

Is hetzelfde als:
C++:
1
DNA dna(s); // of DNA temp(s); DNA dna = temp; ?

edit: en je weet het verschil tussen
C++:
1
2
void foo(object o) {}
void bar(object& o) {}

Als je foo aanroept word eerst een kopie van object gemaakt. Bij bar geef je enkel een referentie door, dat is efficienter en vaak wat je wilt.

[ Voor 17% gewijzigd door user109731 op 31-05-2008 19:46 ]


  • maleadt
  • Registratie: Januari 2006
  • Laatst online: 05-11 22:08
I see. Bedankt voor de link naar het artikel, had er zelf geen gevonden bij gebrek aan goede zoekquery. "Impliciete conversie" was nu niet het eerste dat in mijn hoofd opkwam toen ik dat probleem tegenkwam :P

En ja, ik ben het gebruik van pointer adressen al eens tegengekomen, maar "het zit er nog niet echt in". Met een achtergrond van basic en (eenvoudige) Perl voelen pointers best raar aan in het begin :)
Ik gebruik nu maar enkele keren pointers in mijn programma (enkel waar het absoluut niet anders kan), en was er beginnen mee werken zonder mij eerst eens deftig de documenteren. Leverde dergelijke constructies op:
C++:
1
2
3
int *delta;
delta = new int[dimensie];
delta = functie_die_pointer_naar_array_geeft()

Resultaat, enkel de array die door de externe functie gemaakt was, werd vernietigd, wat natuurlijk resulteerde in immense memory leaks :P (valgrind ftw _/-\o_)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:10

.oisyn

Moderator Devschuur®

Demotivational Speaker

JanDM schreef op zaterdag 31 mei 2008 @ 19:26:
Dus het volgende:
C++:
1
2
string s;
DNA dna = s;

Is hetzelfde als:
C++:
1
DNA dna(s); // of DNA temp(s); DNA dna = temp; ?
Feitelijk is het:
C++:
1
DNA dna(DNA(s))

Aangezien DNA een impliciete copy ctor heeft van de vorm DNA(const DNA&), en omdat er een DNA(const std::string &) bestaat is een std::string dus converteerbaar naar DNA zodat die copy ctor kan worden aangeroepen.

Compilers zijn toegestaan deze extra kopie te vermijden, maar het impliceert wel dat er een accessible copy ctor moet bestaan. Als je de copy ctor private maakt betekent dat dat je de vorm DNA dna = s niet meer kunt gebruiken.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • user109731
  • Registratie: Maart 2004
  • Niet online
.oisyn schreef op zaterdag 31 mei 2008 @ 19:53:
[...]

Feitelijk is het:
C++:
1
DNA dna(DNA(s))
Ah okee, ik twijfelde of er een tijdelijk object werd aangemaakt, maar dat van de copy constructor geeft idd aan dat dat gebeurt (in theorie).
MALEADt schreef op zaterdag 31 mei 2008 @ 19:51:
Leverde dergelijke constructies op:
C++:
1
2
3
int *delta;
delta = new int[dimensie];
delta = functie_die_pointer_naar_array_geeft()

Resultaat, enkel de array die door de externe functie gemaakt was, werd vernietigd, wat natuurlijk resulteerde in immense memory leaks :P (valgrind ftw _/-\o_)
Elke new moet matchen met een delete. Nu alloceer je een blok geheugen, je verandert de pointer, maar het blok blijft in gebruik. Gevolg is idd een memory leak.

Let op het verschil tussen pointers en references. Pointers worden vooral gebruikt in C, terwijl C++ ook references kent. Gebruik normaal references, en pointers alleen als het niet anders kan (een pointer kan NULL zijn en kun je naar een ander object laten verwijzen). Dus:
C++:
1
2
3
4
5
6
7
8
void a(object o) { cout << o.foo(); }
void b(object& o) { cout << o.foo(); } // reference
void c(object* o) { cout << o->foo(); } // pointer

object obj;
a(obj);
b(obj);
c(&obj);

Zoals je ziet maakt het voor de caller niet uit of de functie een reference-naar-object of object vraagt. Bij een pointer maakt dit wel uit. Binnen a en b gebruik je de parameter op dezelfde manier, bij c is het een pointer dus moet je die eerst dereferencen (met ->).

[ Voor 5% gewijzigd door user109731 op 31-05-2008 20:32 ]


  • maleadt
  • Registratie: Januari 2006
  • Laatst online: 05-11 22:08
Leerrijk :) Binnenkort dus eens mijn code herwerken en gebruik maken van references, het geheugengebruik mag best wat naar beneden. Maar eerst moet ik er nog een nasty bug uithalen, een data fetching routine segfaults omdat hij een element buiten de array leest... Ik moet dus ergens de counter van het aantal elementen verhoogd hebben, zonder daadwerkelijk de array met elementen vergroot te hebben. Maar hoe vind je zoiets in godsnaam :X (extra probleem: het is een edge-case dat maar 1 op 10 keer voorkomt :/)

[ Voor 7% gewijzigd door maleadt op 31-05-2008 23:28 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:10

.oisyn

Moderator Devschuur®

Demotivational Speaker

MALEADt schreef op zaterdag 31 mei 2008 @ 23:27:
Maar hoe vind je zoiets in godsnaam :X
Gewoon, in je sourcecode. Dit zijn op zich nog vrij makkelijke dingen, als je je verantwoordelijkheden een beetje goed op orde hebt iig. Doe een search op de variabele die de lengte aangeeft. Als het goed is zal een verandering van de grootte elke keer gepaard moeten gaan met een herallocatie van de array. Idealiter komt dat sowieso maar op 1 plek in de code voor - namelijk een functie die precies dat doet, en de rest maakt allemaal gebruik van die functie. Maar goed, voor dit soort dingen is het sowieso handiger om gewoon een standaard container als std::vector te gebruiken - daarvan weet je dat ze bugvrij zijn.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

MALEADt schreef op zaterdag 31 mei 2008 @ 23:27:
Maar hoe vind je zoiets in godsnaam :X (extra probleem: het is een edge-case dat maar 1 op 10 keer voorkomt :/)
Met dit soort software Wikipedia: BoundsChecker

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:10

.oisyn

Moderator Devschuur®

Demotivational Speaker

Boundschecker gaat je niet helpen bij de zoektocht naar het moment waarop de variabele voor de grootte en de daadwerkelijke grootte van de array beginnen te mismatchen ;)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

.oisyn schreef op maandag 02 juni 2008 @ 01:23:
Boundschecker gaat je niet helpen bij de zoektocht naar het moment waarop de variabele voor de grootte en de daadwerkelijke grootte van de array beginnen te mismatchen ;)
True. Dan gewoon een conditional watch zetten op die variabele.
Pagina: 1