Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

What's the difference?

Status
Not open for further replies.

maluk

Programmer
Oct 12, 2002
79
0
0
SG
Suppose I have two functions, one returns a reference to an object and the other returns an object by value. See below:

Code:
// Assume 'B' is a well-defined class

B& fn(B& b) // returns an object reference
{
    b.i++ ;
    return b ;
}

B fn2(B& b) // returns an object by value
{
   b.i++
   return b ;
}

What is the difference between the statements below?
What is it's impact on efficiency?

Code:
// Assume 'B' has a member function called 'doIt'

    fn().doIt() ;
    fn2().doIt() ;


Rome did not create a great empire by having meetings, they did it by
killing all those who opposed them.

- janvier -
 
Key point: you can't invoke your fn2() as you write in your anippet. Where is fn2() argument?
1st version returns (pass through) a reference to its argument. 2nd version returns new object (copy of its referred argument).
You can't use fn2 #1 and #2 at the same time: they have identical signatures (return value type is not a part of function signature).
1st version is more 'efficient', of course. But it's not so safe as 2nd version. Semantically 1st != 2nd. fn2() #1 pass a reference to any B class object. What's its life time? You may refer to discarded object via this reference (later).
2nd version returns a new object. Be careful: if you don't assign it to any variable, its life time may be too short.
 
ArkM said:
Key point: you can't invoke your fn2() as you write in your anippet. Where is fn2() argument?

Hi!
You are right, I should have put the argument. Guess I have forgotten.

ArkM said:
You can't use fn2 #1 and #2 at the same time: they have identical signatures (return value type is not a part of function signature).

You may have overlooked the code. The #1 is [tt]fn()[/tt] while #2 is [tt]fn2()[/tt].

ArkM said:
1st version is more 'efficient', of course. But it's not so safe as 2nd version. Semantically 1st != 2nd. fn2() #1 pass a reference to any B class object. What's its life time? You may refer to discarded object via this reference (later).

I can't really understand what you mean by this. Well, the lifetime of the value to be returned in #1 is the lifetime of it's argument.

ArkM said:
2nd version returns a new object. Be careful: if you don't assign it to any variable, its life time may be too short.

Provided that there is a copy constructor implemented, the copy constructor is invoked on #2. The returned object is assigned to a temporary as per call to [tt]fn2().doIt()[/tt].


Rome did not create a great empire by having meetings, they did it by
killing all those who opposed them.

- janvier -
 
Let's shortly say,
the first one allow you to do fn().doIt().doSomethingElse() ; on an existing object, for example an internal variable in case if doSoemthingElse is member of returned reference.
Or you may do
fn().doIt() = something;
so if you return a reference to an internal variable, this thing makes often a lot of sence.

Ion Filipski
1c.bmp
 
Note that the "passing along the ref" is quite common when dealing with operations like:
[cout]cout << "Foo" << "Bar" << 42 << endl;[/cout]
It's thanks to the "passing along ostream ref. given as input" you can build nice sequences like that where all operators are actually working on the same ostream instance.

/Per
[sub]
&quot;It was a work of art, flawless, sublime. A triumph equaled only by its monumental failure.&quot;[/sub]
 
lol...
Code:
cout << "Foo" << "Bar" << 42 << endl;
is what I was trying to write...

/Per
[sub]
&quot;It was a work of art, flawless, sublime. A triumph equaled only by its monumental failure.&quot;[/sub]
 
Try this code and see the difference between func1 and func2:
Code:
#include <iostream>

class Test
{
    int val;
public:
    Test(int i) : val(i) { }
    void AddOne() { val++; }
    void AddFive() { val+=5; }
    void Output() { std::cout << val << std::endl; }
};

Test& func1(Test& t)
{
    t.AddOne();
    return t;
}

Test func2(Test& t)
{
    t.AddOne();
    return t;
}

int main()
{
    Test t1(1);
    func1(t1).AddFive();
    t1.Output();

    Test t2(1);
    func2(t2).AddFive();
    t2.Output();
}
Of course the reason AddFive doesn't change t2 is because a copy is made when func2 returns, and that copy has five added to it. The fact that it is less efficient to make a copy is less important in this instance than the fact that the two functions cause different behaviors.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top