/ 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
Returnering af reference til objekt [C++]
Fra : Kasper Kristensen


Dato : 08-08-03 22:47

Hej gruppe.

Jeg vil gerne returnere et relativt stort objekt, så jeg vil foretrække det
bliver returneret som reference for at slippe for unødig kopiering.

Jeg er nået frem til følgende kodesnip som ser ud til at virke (kompilerer
uden warnings):

Object& MyClass::getObject()
{
Object* result=new Object();

//blah, blah blah

return *result;

}

Mine spørgsmål er nu:

1) Returnerer jeg rent faktisk kun referencen eller sker der en implicit
kopiering?
2) Hvem skal nu slette result? Altså, hvis getObject() kaldes igen og igen,
vil hukommelsen så ikke fyldes op af result kopier?

Mvh.

Kasper



 
 
Socketd (08-08-2003)
Kommentar
Fra : Socketd


Dato : 08-08-03 14:14

On Fri, 8 Aug 2003 14:46:34 -0700
"Kasper Kristensen" <spam_me_senseless_khk@mindgroup.dk> wrote:

> Hej gruppe.

Dav dav

> Jeg vil gerne returnere et relativt stort objekt, så jeg vil
> foretrække det bliver returneret som reference for at slippe for
> unødig kopiering.
>
> Jeg er nået frem til følgende kodesnip som ser ud til at virke
> (kompilerer uden warnings):
>
> Object& MyClass::getObject()
> {
> Object* result=new Object();
>
> //blah, blah blah
>
> return *result;
>
> }
>
> Mine spørgsmål er nu:
>
> 1) Returnerer jeg rent faktisk kun referencen eller sker der en >
> implicit kopiering?

Der sker ingen kopiering.

> 2) Hvem skal nu slette result? Altså, hvis getObject() kaldes igen og
> igen, vil hukommelsen så ikke fyldes op af result kopier?

Jo, derfor bør du returnere en pointer, så brugeren kan se at det er et
"heap objekt" han får. Eventuelt kan du også lave en:
void Myclass::getObject(Object *ob)

Men så vil det måske være bedre at kalde den setObject!?!?

mvh
socketd

Troels Thomsen (08-08-2003)
Kommentar
Fra : Troels Thomsen


Dato : 08-08-03 14:21

> Jo, derfor bør du returnere en pointer,

Enig,
Jeg har set nogen gøre noget i denne stil (sikkert fordi de ikke kan lide ->
operatoren og hellere vil bruge dot ?):

Object* Myclass::getObject()
{
return new Object();
}

og når du bruger den:

Object& obj = *getObject()
obj.whatever()

mvh Troels



Mogens Hansen (08-08-2003)
Kommentar
Fra : Mogens Hansen


Dato : 08-08-03 20:33


"Socketd" <db@NO_SPAM_traceroute.dk> wrote in message
news:20030808151345.28a9b0c8.db@NO_SPAM_traceroute.dk...

>> 2) Hvem skal nu slette result? Altså, hvis getObject() kaldes igen og
>> igen, vil hukommelsen så ikke fyldes op af result kopier?
>
>Jo, derfor bør du returnere en pointer, så brugeren kan se at det er et
>"heap objekt" han får.

Blot fordi man får en pointer til et objekt, kan man ikke forvente at man
har ansvaret for at nedlægge det.
F.eks. returnerer "std::string::c_str()" en pointer til en nul-termineret
streng, man man har absolut ikke lov til at frigive den.

En væsentlig forskel mellem at bruge pointer eller reference er at en
pointer behøver ikke at pege på den noget - den kan være 0.
En reference vil altid være et alias for et eksisterende objekt - eller har
man et defekt program.

> Eventuelt kan du også lave en:
>void Myclass::getObject(Object *ob)

Det vil ikke virke hvis du havde tænkt af funktionen skal have
tilnærmelsesvis samme funktion som i det oprindelige spørgsmål.
Funktionen skal mindst tage en reference til en pointer eller en pointer til
en pointer.

Venlig hilsen

Mogens Hansen



Mogens Hansen (08-08-2003)
Kommentar
Fra : Mogens Hansen


Dato : 08-08-03 20:33


"Kasper Kristensen" <spam_me_senseless_khk@mindgroup.dk> wrote

> Jeg vil gerne returnere et relativt stort objekt, så jeg vil foretrække
det
> bliver returneret som reference for at slippe for unødig kopiering.

Er du sikker på at du har et problem, der trænger til at blive løst ?

Har du undersøgt om der rent faktisk bliver lavet en kopi ?
Hvis du laver funktionen som
foo bar()
{
foo result;
// ...
return result;
}
har compileren lov til at undlade at lave en unødig kopiering.
Det kaldes "return value optimization".
Test det hvor compileren optimerer.

Har du undersøgt i hvilken udstrækning den ekstra kopi udgør et problem.
Igen skal du måle på optimeret kode.

Endelig er det værd at undersøge om du i givet fald kan gøre kopiering af
objekter billigere, f.eks. vha. reference counting.

[8<8<8<]
> 1) Returnerer jeg rent faktisk kun referencen eller sker der en implicit
> kopiering?

Nej.

> 2) Hvem skal nu slette result?

Nogen.

Hvis du i stedet bruger en smart-pointer og f.eks. laver funktionen som

std::auto_ptr<Object> MyClass::getObject()
{
std::auto_ptr<Object> result(new Object);
// ...
return result;
}

så er det svært at undgå at objektet bliver nedlagt.

Venlig hilsen

Mogens Hansen



Prankster Kineses (08-08-2003)
Kommentar
Fra : Prankster Kineses


Dato : 08-08-03 20:52


"Mogens Hansen" <mogens_h@dk-online.dk> wrote in message
news:bh0tro$mmm$1@news.cybercity.dk...
>
> "Kasper Kristensen" <spam_me_senseless_khk@mindgroup.dk> wrote
>
> > Jeg vil gerne returnere et relativt stort objekt, så jeg vil foretrække
> det
> > bliver returneret som reference for at slippe for unødig kopiering.
>
> Er du sikker på at du har et problem, der trænger til at blive løst ?
>

Nej egentlig ikke. Jeg har for vane altid at bruge helt almindelig
returnering uden reference eller noget, men så påpegede een for mig, at for
meget store objekter og ved hyppige kald bør man returnere en reference
eller pointer for at undgå kopiering.

> Har du undersøgt om der rent faktisk bliver lavet en kopi ?

Nej, hvordan ser jeg det?

> Hvis du laver funktionen som
> foo bar()
> {
> foo result;
> // ...
> return result;
> }
> har compileren lov til at undlade at lave en unødig kopiering.
> Det kaldes "return value optimization".
> Test det hvor compileren optimerer.
>

Gælder det ikke kun for "primitives" som int, double, etc og klasser som
indeholder primitives? Der er tale om en større klasse som indeholder flere
andre klasser. De har dog alle, så vidt jeg kan se, en copy-constructor.

> Har du undersøgt i hvilken udstrækning den ekstra kopi udgør et problem.
> Igen skal du måle på optimeret kode.
>
Jeg er ikke sikker på det er et decideret problem, jeg ville bare være på
den sikre side og gøre det ordentligt. Som sagt så har jeg altid selv bare
returneret på vanlig vis uden at tænke på performance.

> Endelig er det værd at undersøge om du i givet fald kan gøre kopiering af
> objekter billigere, f.eks. vha. reference counting.
>
> [8<8<8<]
> > 1) Returnerer jeg rent faktisk kun referencen eller sker der en implicit
> > kopiering?
>
> Nej.
>
> > 2) Hvem skal nu slette result?
>
> Nogen.
>
> Hvis du i stedet bruger en smart-pointer og f.eks. laver funktionen som
>
> std::auto_ptr<Object> MyClass::getObject()
> {
> std::auto_ptr<Object> result(new Object);
> // ...
> return result;
> }
>
> så er det svært at undgå at objektet bliver nedlagt.
>

Hm, kender dem ikke. Lyder smart, så det vil jeg kigge nærmere på.

> Venlig hilsen
>
> Mogens Hansen

Tak for et grundigt svar.

Kasper
>
>



Mogens Hansen (08-08-2003)
Kommentar
Fra : Mogens Hansen


Dato : 08-08-03 22:43


"Prankster Kineses" <spam.me.senseless@spam.spam> wrote in message
news:bh0v03$pmt$1@sunsite.dk...

[8<8<8<]
> > Er du sikker på at du har et problem, der trænger til at blive løst ?
> >
> Nej egentlig ikke.

Det er nok det mest almindelige.

> Jeg har for vane altid at bruge helt almindelig
> returnering uden reference eller noget,

Det er et fornuftigt udgangspunkt - for typer med value semantik som f.eks.
dato-objekter.

> men så påpegede een for mig, at for
> meget store objekter og ved hyppige kald bør man returnere en reference
> eller pointer for at undgå kopiering.

Det er ikke helt forkert men heller ikke helt rigtigt.
Men check at der er et problem, inden du begynder at optimere.

>
> > Har du undersøgt om der rent faktisk bliver lavet en kopi ?
>
> Nej, hvordan ser jeg det?

Du kan f.eks. lave en copy-constructor og se om den bliver kaldt - f.eks.
med en debugger.

[8<8<8<]
> Gælder det ikke kun for "primitives" som int, double, etc og klasser som
> indeholder primitives?

Nej, bestemt ikke.
Det gælder alle klasser, men compileren har lov til at lade være med at
optimere det ekstra objekt væk.
Forskellige compilere har forskellige kriterier for hvornår de optimerer det
væk.

F.eks. giver:
<C++ kode>
#include <iostream>
#include <string>

class foo
{
public:
foo(const char* text_arg);
foo(const foo& source_arg);
~foo();

private:
std::string text;
};

foo::foo(const char* text_arg) :
text(text_arg)
{
std::cout << "constructor foo::foo called" << std::endl;
}

foo::foo(const foo& source_arg) :
text(source_arg.text)
{
std::cout << "copy constructor foo::foo called" << std::endl;
}

foo:foo()
{
std::cout << "destructor foo:foo called" << std::endl;
}


foo get_foo(const char* text_arg)
{
foo result(text_arg);
return result;
}

int main()
{
foo f = get_foo("bar");
}
</C++ kode>

følgende
<output>
constructor foo::foo called
destructor foo:foo called
</output>
når det oversættes med Intel C++ V7.0 med optimering slået til

[8<8<8<]
> > Har du undersøgt i hvilken udstrækning den ekstra kopi udgør et problem.
> > Igen skal du måle på optimeret kode.
> >
> Jeg er ikke sikker på det er et decideret problem, jeg ville bare være

> den sikre side og gøre det ordentligt.

Men hvad er ordentligt ?
Alt andet lige er det bedst at have funktioner, der er nemme og sikre at
bruge.
Hvis det viser sig at der er et performance problem, så gør enten klassen
billigere at kopiere eller lad funktionen returnere et std::auto_ptr objekt.
Det er ofte unødvendigt farligt at have en funktion, der allokerer noget og
det kun står i dokumentationen at man skal huske at frigive det.

Venlig hilsen

Mogens Hansen




Søg
Reklame
Statistik
Spørgsmål : 177459
Tips : 31964
Nyheder : 719565
Indlæg : 6408186
Brugere : 218881

Månedens bedste
Årets bedste
Sidste års bedste