Toon posts:

[c++] kopie van object vermijden bij functie aanroep en exit

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik heb vaak dat een functie een object moet veranderen, maar dan een veranderde kopie moet teruggeven, en niet het origineel aanpassen.

Het meest simpele is:
code:
1
2
3
4
5
6
MyClass PasObjectAan( MyClass x )
{
 // doe iets met x
 // (aangezien dit een kopie is wordt het origineel waarmee je de functie aanroept niet veranderd)
 return x;          
}


Als ik nu ergens doe: MyClass b = PasObjectAan(a) worden er volgens mij drie kopieën gemaakt: bij het aanroepen van de functie, bij het returnen, en bij het assignen aan b.

De kopie bij het aanroepen kan worden vermeden door een const MyClass &x als parameter te gebruiken, alleen dan kun je x in de functie niet veranderen, dus moet je daar alsnog een kopie maken.

Mijn vraag is nu: als ik in die functie een kopie maak, hoe kan ik dan die kopie returnen zonder dat die bij het returnen nog een keer gekopieerd wordt, en bij het assignen (dus waar ik het resultaat van de functie uiteindelijk bewaar zeg maar) nóg een keer?

Een mogelijkheid is de functie een pointer laten returnen en dan in de functie een instantie new'en, maar ik wil graag geen pointer maar een normaal object returnen.
Een andere mogelijkheid is van het object waar ik uiteindelijk het resultaat in wil hebben (in het aanroep voorbeeld is dat b) een reference of pointer meegeven. De functie wordt dan void en schrijft het resultaat direct naar het uiteindelijke object. Maar da's ook zo lelijk, ik wil graag zoveel mogelijk die notatie van b = functie(a) aanhouden.

Ergens in de functie moet de instantie worden gemaakt die hij gaat returnen. Is er een mogelijkheid dat ik in de functie al bij die uiteindelijke return instantie kan komen? Of instantieert hij die pas op het eind?

Een reference returnen leek me ook niet de bedoeling, want als ik een tijdelijk object binnen de functie maak is die weer weg als hij de functie verlaat, en is die reference ongeldig.
Of kan ik toch iets doen van de vorm MyClass &b = PasObjectAan(a), en hoe moet die functie er dan precies uitzien?

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Mijn vraag is nu: als ik in die functie een kopie maak, hoe kan ik dan die kopie returnen zonder dat die bij het returnen nog een keer gekopieerd wordt, en bij het assignen (dus waar ik het resultaat van de functie uiteindelijk bewaar zeg maar) nóg een keer?
Compilers zijn toegestaan om return-value-optimization toe te passen, waarbij extra kopies vermeden worden. In de praktijk kan dat betekenen dat de b die je construct in de functie in werkelijkheid de MyClass is die je construct met het resultaat van de functie. Als je die laatste al hebt geconstruct wordt het een assignment en dan kan de kopie helaas niet vermeden worden.

Eventueel kun je ervoor kiezen om gewoon te stellen dat PasObjectAan() geen kopie maakt, en dat dat de verantwoordelijkheid is voor de aanroeper van de functie als die het origineel wilt behouden.

[ Voor 14% gewijzigd door .oisyn op 29-05-2008 16:20 ]

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.


  • leuk_he
  • Registratie: Augustus 2000
  • Laatst online: 01-11 22:03

leuk_he

1. Controleer de kabel!

MyClass b=a; ModifyB(&B) ;

klink toch niet zo beroerd?

Need more data. We want your specs. Ik ben ook maar dom. anders: forum, ff reggen, ff topic maken
En als je een oplossing hebt gevonden laat het ook ujb ff in dit topic horen.


  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
B PasAaan(const B& b)
{
   B copy(b);
   copy.modify();
   return copy;
}

// of 

B PasAan(const B& b)
{
  return B(b, aanpassing);
}

Dit worden dus telkens 2 copies, maar met wat .oisyn zegt herleidt de compiler dit meestal tot 1 enkele. (zie de C++ FAQ lite)

ASSUME makes an ASS out of U and ME


  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
Waarom is PasObjectAan geen member van MyClass? Dan kun je de copy constructor gebruiken om een copy van het origineel te maken waarna je simpelweg een aanroep doet naar PasObjectAan:

code:
1
2
MyClass b = a;
b.PasObjectAan();

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

PrisonerOfPain schreef op donderdag 29 mei 2008 @ 19:57:
Waarom is PasObjectAan geen member van MyClass? Dan kun je de copy constructor gebruiken om een copy van het origineel te maken waarna je simpelweg een aanroep doet naar PasObjectAan:

code:
1
2
MyClass b = a;
b.PasObjectAan();
Daar hoeft het natuurlijk geen member voor te zijn. PasObjectAan(MyClass&) kan ook.

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.


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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Feitelijk wil je gewoon move constructors, en er is goed nieuws: dat komt er ook aan. Dmv r-value references. Het nadeel is wel dat je nog even moet wachten voordat je compiler het geimplementeerd heeft, de standaard is nog niet eens af ;). Je zou al wel kunnen experimenteren met de nieuwste GCC of met ConceptGCC, waar het volgens mij ook in geïmplementeerd is.

[ Voor 3% gewijzigd door .oisyn op 30-05-2008 12:39 ]

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.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 01:42
Is het toeval dat je in de TS precies pass-by-value en pass-by-const-reference als opties noemt? Het lijkt met dat de derde optie (pass-by-reference) juist precies is wat je wil:

C++:
1
2
3
4
void PasObjectAan( MyClass &x )
{
 // doe iets met x
}

Simpel genoeg?

Je kunt over de return value nog discussiëren trouwens. Vaak wordt een reference naar het argument teruggegeven bijvoorbeeld. Ik raad void aan zodat dit soort code niet compileert:
C++:
1
MyClass nieuwe = PasObjectAan(oude);

Deze code doet namelijk vermoeden dat de auteur denkt dat PasObjectAan() het argument ongewijzigd laat en de wijziging in een nieuw object retourneert. Dat is een fout die je liever tijdens het compileren al detecteert.

  • ATS
  • Registratie: September 2001
  • Laatst online: 29-10 18:37

ATS

Hoewel je er niet op ingaat wat je MyClass zoal inhoudt, doet je vraag vermoeden dat het een relatief complex object is dat ook daadwerkelijk tijd kost om te kopieren. Als dat niet het geval is, dan zou ik me er verder ook niet druk om maken. Als het inderdaad een vrij groot object is, dan zou je ook kunnen kijken of je er een implicitly shared class van zou kunnen maken. Dat wil zeggen dat je de data in je klasse onderbrengt in een private class, en deze instantie achter de schermen deelt tussen kopieën van je object. Uiteraard heb je dan wel reference counting nodig en moet je als je gaat schrijven alsnog een kopie van je private data maken (copy on write).

In jouw geval zou dit betekenen dat je op het moment dat je PasObjectAan gaat rommelen in zijn kopie van je object, je object de private data zou gaan kopiëren. Je data wordt echter niet opnieuw gekopieert op het moment dat het resultaat van de functie wordt geassigned aan je variabele, omdat je dan alleen een shallow copy hoeft te maken. Op deze manier kan je je PasObjectAan functie gewoon een const MyClass& als argument geven. Uiteraard kan je compiler e.e.a. nog verder optimaliseren, maar dat ligt nogal aan je compiler en je opties.

Overigens vind ik helemaal niet gek om wel degelijk je functie als void PasObjectAan(MyClass*) te declareren. Als het je bedoeling is om een object aan te passen, dan moet je het IMHO ook niet vreemd vinden als je functie ook daadwerkelijk het object aan past. De oplossing dat je PasObjectAan een member maakt van MyClass kan natuurlijk ook, maar het is afhankelijk van het ontwerp van je applicatie of dat logisch is.

My opinions may have changed, but not the fact that I am right. -- Ashleigh Brilliant

Pagina: 1