return type vs passing a reference

C

Carl Forsman

there are 2 ways to return a value from a function
====================
1) passing a reference as parameter - the following will return time

void Table::Get(char* FieldName, *SYSTEMTIME time)
{
_variant_t vtValue;
vtValue = m_Rec->Fields->GetItem(FieldName)->GetValue();

if (vtValue.vt == VT_NULL) {
return NULL;
}
VariantTimeToSystemTimeWithMilliseconds (vtValue.date, time);
}
====================
2) use return keyword
SYSTEMTIME Table::Get(char* FieldName)
{
_variant_t vtValue;
vtValue = m_Rec->Fields->GetItem(FieldName)->GetValue();

if (vtValue.vt == VT_NULL) {
return NULL;
}
SYSTEMTIME m_st;
VariantTimeToSystemTimeWithMilliseconds (vtValue.date, &m_st);
return m_st;
}

====================

Can I only use the 1st way to returning value from a function? as
both ways is doing the same thing to return a value.

Then I can make code more clean to have all function to void return
type and if I need a return value from a function, I just pass in the
pointer that I want the function to return (e.g. *SYSTEMTIME time)
 
I

Ian Collins

Carl said:
Then I can make code more clean to have all function to void return
type and if I need a return value from a function, I just pass in the
pointer that I want the function to return (e.g. *SYSTEMTIME time)

You can do this, but I doubt many would agree with your definition of clean.

Doing what you describe is most often used for function templates where
the parameter types are used to resolve the argument types.

Else where, it just leads to clutter. You have to use variables
whenever you call a function, whether you want to retain the result or
not. so rather than simply writing

int n = doSomething();

you end up with

int n;
doSomething( n );

manageable for simple variables, but useless for constants or objects
such as std::auto_ptr that require initialisation.
 
C

Carl Forsman

You can do this, but I doubt many would agree with your definition of clean.

Doing what you describe is most often used for function templates where
the parameter types are used to resolve the argument types.

Else where, it just leads to clutter. You have to use variables
whenever you call a function, whether you want to retain the result or
not. so rather than simply writing

int n = doSomething();

you end up with

int n;
doSomething( n );

manageable for simple variables, but useless for constants or objects
such as std::auto_ptr that require initialisation.

so you mean I better use Way #2 - (return value) when I want to return
something in a "normal" way?
 
I

Ian Collins

Carl said:
so you mean I better use Way #2 - (return value) when I want to return
something in a "normal" way?

With the exception of function templates, yes.
 
J

James Kanze

You can do this, but I doubt many would agree with your
definition of clean.
Doing what you describe is most often used for function
templates where the parameter types are used to resolve the
argument types.

Was most often used. In modern C++, there are other solutions,
and I think most people would prefer to use a return value, and
specify the return type explicitly, i.e. f< int >(), rather than
f( int& ). (It's also possible to design the function to return
a proxy in which the return type is chosen automatically.)

The most frequent use I've seen for using a reference to return
a value is when the function should return more than one value.
Others occasional uses are when the returned value is a
modification of an object which is also used as an in argument,
and when the return type is very expensive to copy, e.g. an
std::list said:
Elsewhere, it just leads to clutter.  You have to use
variables whenever you call a function, whether you want to
retain the result or not.  so rather than simply writing
int n = doSomething();
you end up with
int n;
doSomething( n );
manageable for simple variables, but useless for constants or
objects such as std::auto_ptr that require initialisation.

The real problem is when the return type is something that can
be used in further expressions. Which is clearer:
(-b + sqrt( b*b - 4*a*c))/(2*a)
or even
div( add( neg( b ),
sqrt( sub( mul( b, b ), mul( mul( 4, a ), c ) ) ) ),
mul( 2, a ) )
, compared to
BigNumber bSquared ;
mul( &bSquared, b, b ) ;
BigNumber aTimesC ;
mul( &aTimesC, a, c ) ;
BigNumber aTimesCTimes4 ;
mul( &aTimesCTimes4, 4, aTimesC ) ;
BigNumber sum ;
add( &sum, bSquared, aTimesCTimes4 ) ;
BigNumber delta ;
sqrt( &delta, sum ) ;
// ...
 
R

.rhavin grobert

Can I only use the 1st way to returning value from a function?  as
both ways is doing the same thing to return a value.

if you return non-trivial object, some additional ctors/dtros for
temporarily objects may be included. if you have a "filler"-function,
that fill a struct with values for exmpl, you have two ways:

struct X { /* ... */ };
X foo = FillFoo()

and

struct X { /* ... */ };
X foo;
FillFoo(foo);

the second way just uses one struct and needs one construction. the
first way needs a struct inside FillFoo(), sometimes a temporary for
transfer and the foo outside, so you`ll end with 2-3 ctors.

So if you return natives (int, double, ...) or pointers to statics,
use return-type, otherwise use referenced parameters.
 
M

mail.dsp

there are 2 ways to return a value from a function
====================
1) passing a reference as parameter - the following will return time

void Table::Get(char* FieldName, *SYSTEMTIME time)
{
_variant_t vtValue;
vtValue = m_Rec->Fields->GetItem(FieldName)->GetValue();

if (vtValue.vt == VT_NULL) {
return NULL;
}
VariantTimeToSystemTimeWithMilliseconds (vtValue.date, time);}

====================
2) use return keyword
SYSTEMTIME Table::Get(char* FieldName)
{
_variant_t vtValue;
vtValue = m_Rec->Fields->GetItem(FieldName)->GetValue();

if (vtValue.vt == VT_NULL) {
return NULL;
}
SYSTEMTIME m_st;
VariantTimeToSystemTimeWithMilliseconds (vtValue.date, &m_st);
return m_st;

}

====================

Can I only use the 1st way to returning value from a function? as
both ways is doing the same thing to return a value.

Then I can make code more clean to have all function to void return
type and if I need a return value from a function, I just pass in the
pointer that I want the function to return (e.g. *SYSTEMTIME time)

If you think the returned object from function may generate any kind
of exception during its construction or assignment and any kind of
memory leak or resource allocation/deallocation misbehave then it
would be better to use reference technique otherwise you can use
return technique. As you can see in STL stack class pop() method
doesn't return anything. You'll have to use top() method to retrieve
top most element of stack.
 
I

Ian Collins

If you think the returned object from function may generate any kind
of exception during its construction or assignment and any kind of
memory leak or resource allocation/deallocation misbehave then it
would be better to use reference technique otherwise you can use
return technique.

Why? The exception is still going to have to be caught.
 
T

Triple-DES

Why?  The exception is still going to have to be caught.

I think his point is that if the function is a non-const member
function, and the "return t;" may throw (because T's copy ctor may
throw), the object will not be in the same state as before the
operation, making it impossible to give the strong exception safety
guarantee.
 
I

Ian Collins

Triple-DES said:
I think his point is that if the function is a non-const member
function, and the "return t;" may throw (because T's copy ctor may
throw), the object will not be in the same state as before the
operation, making it impossible to give the strong exception safety
guarantee.

I can just as easily say that "passing by reference" may throw because
T's assignment operator may throw.
 
J

James Kanze

if you return non-trivial object, some additional ctors/dtros
for temporarily objects may be included. if you have a
"filler"-function, that fill a struct with values for exmpl,
you have two ways:

struct X { /* ... */ };
X foo = FillFoo()

struct X { /* ... */ };
X foo;
FillFoo(foo);
the second way just uses one struct and needs one
construction.

The second way requires constructing the object before you know
how to initialize it. Depending on the type of object, it may
not be possible (many types don't support default construction),
or it may be overly expensive in runtime (construct the object
with one set of values, then tear it down and construct it with
another).
the first way needs a struct inside FillFoo(), sometimes a
temporary for transfer and the foo outside, so you`ll end with
2-3 ctors.
So if you return natives (int, double, ...) or pointers to
statics, use return-type, otherwise use referenced parameters.

The rule is to use the return value whenever possible. If the
profiler later shows that this does cause a slow down, then you
can change, but you certainly shouldn't worry about it before
it's a problem.
 
J

James Kanze

On Nov 16, 1:37 am, Carl Forsman <[email protected]> wrote:

[...]
If you think the returned object from function may generate
any kind of exception during its construction or assignment
and any kind of memory leak or resource
allocation/deallocation misbehave then it would be better to
use reference technique otherwise you can use return
technique.

This is simply wrong. If the object is going to leak, it's
going to leak in both cases. (Well designed and implemented
objects don't leak, even if there is an exception.)
As you can see in STL stack class pop() method doesn't return
anything. You'll have to use top() method to retrieve top most
element of stack.

That's a totally different issue. The std::stack<>::pop()
doesn't return anything; the question here is how to return
something. And the justification in the case of pop has nothing
to do with possible resource leaks; it's about maintaining a
strong exception guarantee, in which every action either returns
normally or makes NO change in state. This strong guarantee
isn't really necessary that often, and returning the value via a
reference wouldn't make it any easier to meet.
 
J

James Kanze

I think his point is that if the function is a non-const
member function, and the "return t;" may throw (because T's
copy ctor may throw), the object will not be in the same state
as before the operation, making it impossible to give the
strong exception safety guarantee.

As a general rule, if the strong exception safety guarantee is
required, mutators shouldn't return anything but return codes.
The strong exception safety guarantee isn't needed that often,
however (or rather, when it is needed, it is generally needed at
a higher level of granularity, for tranactions involving several
objects).
 
J

James Kanze

I can just as easily say that "passing by reference" may throw
because T's assignment operator may throw.

Yes, but you could do the assignment before removing the object
from the stack, so you'd still have the strong guarantee.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top