Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Small question about return statements...

Reply
Thread Tools

Small question about return statements...

 
 
Dave Rahardja
Guest
Posts: n/a
 
      01-27-2007
On Sat, 27 Jan 2007 17:31:28 GMT, Lionel B <(E-Mail Removed)> wrote:

>That looks very much like C code. The C++ equivalent would probably be to
>have the function take references rather than pointers... which you seem to
>have dismissed in a previous reply in this thread as "not pretty". How is
>the above code prettier?


Yes, the example is very much C code. I personally prefer the tuple
implementation for its convenience (i.e. it can be a struct (tuple) if you
want, or fill in individual variables (tie) if you want, or a mixture of
both).

I guess having worked in the embedded world for so long has caused me to
prematurely optimize at the very low level. Shame on me.

>Um, surely std::vector would not be appropriate here - as you are
>obviously aware of, as in a previous reply you mentioned using
>boost::tuple (std:air would be ok too, I guess).
>
>Are you actually two different people?


I used to have multiple personalities, but we're fine now.

I'm the software architecture lead on a reasonably large project, and I have
to constantly switch between very high-level architectural concerns and high
frequency, low-level bit-twiddling behavior that can cripple the system with
inefficiency. I've managed to stay pure to good OOA/OOD principles over the
vast majority of the design, but every now and then Mr. Hyde pops out and I
want to optimize! Bad Mr. Hyde.

>I imagine a half-decent optimising compiler would eliminate any overheads
>in the struct/boost::tuple/std:air solutions (ok, that may not be a good
>argument for embedded systems). Also, I'm not sure exceptions would be
>necessary/appropriate, depending on how you view an "error
>condition". But you might just as well return your error code as
>part of your struct/tuple.


You are correct.

As a side note, Using C++ exceptions in a real-time system (like mine is)
makes me uneasy because of its timing concerns and its ambiguous semantics
(with respect to my application domain). In my project, every error is
expected by definition, and any unexpected error (exception) is
short-circuited to either unexpected() or terminate(), which causes the system
to reset to a safe state.

-dr
 
Reply With Quote
 
 
 
 
Alan Johnson
Guest
Posts: n/a
 
      01-27-2007
Dave Rahardja wrote:
> They're both ugly and kludgy. For a more elegant solution, see boost.tuple. It
> lets you write code like this:
>
> #include "boost/tuple.hpp"
>
> using boost::tuples::tuple;
> using boost::tuples::make_tuple;
> using boost::tuples::tie;
>
> tuple<int, int> fn()
> {
> return make_tuple(1, 2);
> }
>
> int main()
> {
> int my_a;
> int my_b;
> tie(my_a, my_b) = fn(); // Assigns values to my_a and my_b
> }


While this is one of the more elegant solutions, I still find it a bit
"kludgy". Specifically the variables that receive the return values
have to be default constructed, which is annoying for types that do
something non-trivial in their constructor (or types that don't even
have a default constructor).

Unfortunately I think this might be the closest we can get with a pure
library solution.

--
Alan Johnson
 
Reply With Quote
 
 
 
 
Dave Rahardja
Guest
Posts: n/a
 
      01-28-2007
On Sat, 27 Jan 2007 12:50:57 -0800, Alan Johnson <(E-Mail Removed)> wrote:

>Dave Rahardja wrote:
>> They're both ugly and kludgy. For a more elegant solution, see boost.tuple. It
>> lets you write code like this:
>>
>> #include "boost/tuple.hpp"
>>
>> using boost::tuples::tuple;
>> using boost::tuples::make_tuple;
>> using boost::tuples::tie;
>>
>> tuple<int, int> fn()
>> {
>> return make_tuple(1, 2);
>> }
>>
>> int main()
>> {
>> int my_a;
>> int my_b;
>> tie(my_a, my_b) = fn(); // Assigns values to my_a and my_b
>> }

>
>While this is one of the more elegant solutions, I still find it a bit
>"kludgy". Specifically the variables that receive the return values
>have to be default constructed, which is annoying for types that do
>something non-trivial in their constructor (or types that don't even
>have a default constructor).
>
>Unfortunately I think this might be the closest we can get with a pure
>library solution.


Actually, you can do this:

int main()
{
tuple<int, int> result = fn();
int my_a = result.get<0>;
int my_b = result.get<1>;
}

With the appropriate using statements, etc.

-dr
 
Reply With Quote
 
Alan Johnson
Guest
Posts: n/a
 
      01-28-2007
Dave Rahardja wrote:
> On Sat, 27 Jan 2007 12:50:57 -0800, Alan Johnson <(E-Mail Removed)> wrote:
>
>> Dave Rahardja wrote:
>>> They're both ugly and kludgy. For a more elegant solution, see boost.tuple. It
>>> lets you write code like this:
>>>
>>> #include "boost/tuple.hpp"
>>>
>>> using boost::tuples::tuple;
>>> using boost::tuples::make_tuple;
>>> using boost::tuples::tie;
>>>
>>> tuple<int, int> fn()
>>> {
>>> return make_tuple(1, 2);
>>> }
>>>
>>> int main()
>>> {
>>> int my_a;
>>> int my_b;
>>> tie(my_a, my_b) = fn(); // Assigns values to my_a and my_b
>>> }

>> While this is one of the more elegant solutions, I still find it a bit
>> "kludgy". Specifically the variables that receive the return values
>> have to be default constructed, which is annoying for types that do
>> something non-trivial in their constructor (or types that don't even
>> have a default constructor).
>>
>> Unfortunately I think this might be the closest we can get with a pure
>> library solution.

>
> Actually, you can do this:
>
> int main()
> {
> tuple<int, int> result = fn();
> int my_a = result.get<0>;
> int my_b = result.get<1>;
> }
>
> With the appropriate using statements, etc.
>
> -dr


Now you have superfluous copy construction instead. Perhaps:

tuple<T1, T2> result = fn() ;
T1 & a = result.get<0>() ;
T2 & b = result.get<1>() ;

Though this is still annoyingly verbose. This seems like something the
language should take care of for me. Something like:

[T1, T2] fn()
{
return [T1(), T2()] ;
}

int main()
{
[T1 a, T2 b] = fn() ;
}



--
Alan Johnson.
 
Reply With Quote
 
BobR
Guest
Posts: n/a
 
      01-28-2007
SpiralCorp wrote:
>>
>>>What do you guys think, whats the proper way of doing it?

>>
>>It is kosher and is a fine way to return multiple values from a
>>function. Another way is to define a struct that contains multiple
>>values, and use the struct as the function's return.
>>- - >>Scott McPhillips [VC++ MVP]

>
> Good to know. I'll keep using the reference method as I'm not so
> familiar with structs yet, but I'll make a note for when I am. Thanks
> for the help.
> ---
> SpiralCorp


'struct' and 'class' are very useful tools. I'll give you a short example:

#include <iostream>

struct Thing{ // same as "class Thing{ public:"
int Num;
char Ch;
}; // note semicolon at end

void Func( Thing &Th ){
Th.Num = 42;
Th.Ch = 'Z';
return;
}

int main(){
Thing Mine;
Func( Mine );
std::cout<<"Mine: Num="<<Mine.Num<<" Ch="
<<Mine.Ch<<std::endl;

int A( Mine.Num );
char B( Mine.Ch );
std::cout<<"int A="<<A<<" char B="<<B<<std::endl;

return 0;
}

That's only the very tip of the iceberg. <G>
Bob R
POVrookie

 
Reply With Quote
 
BobR
Guest
Posts: n/a
 
      01-28-2007
Ian Collins wrote:
> Grizlyk wrote:
>>SpiralCorp wrote:
>>
>>>int divide (int a, int b){
>>>int r;

>>
>>uninitialized variable is wrong way, at least set "r" to zero
>> int r=0;

>
> No, just use
>
> int r=a/b;
>


No, just use:

int r( a/b );

<G>

......next....

Bob <G> R
POVrookie

 
Reply With Quote
 
Jerry Coffin
Guest
Posts: n/a
 
      01-28-2007
In article <SRVuh.476062$(E-Mail Removed)>,
http://www.velocityreviews.com/forums/(E-Mail Removed) says...
> Ian Collins wrote:
> > Grizlyk wrote:
> >>SpiralCorp wrote:
> >>
> >>>int divide (int a, int b){
> >>>int r;
> >>
> >>uninitialized variable is wrong way, at least set "r" to zero
> >> int r=0;

> >
> > No, just use
> >
> > int r=a/b;
> >

>
> No, just use:
>
> int r( a/b );


Or just 'return a/b;'

--
Later,
Jerry.

The universe is a figment of its own imagination.
 
Reply With Quote
 
Greg Herlihy
Guest
Posts: n/a
 
      01-28-2007



On 1/27/07 9:08 PM, in article (E-Mail Removed),
"Jerry Coffin" <(E-Mail Removed)> wrote:

> In article <SRVuh.476062$(E-Mail Removed)>,
> (E-Mail Removed) says...
>> Ian Collins wrote:
>>> Grizlyk wrote:
>>>> SpiralCorp wrote:
>>>>
>>>>> int divide (int a, int b){
>>>>> int r;
>>>>
>>>> uninitialized variable is wrong way, at least set "r" to zero
>>>> int r=0;
>>>
>>> No, just use
>>>
>>> int r=a/b;
>>>

>>
>> No, just use:
>>
>> int r( a/b );

>
> Or just 'return a/b;'


None of these implementations are satisfactory because none answer the
question: what is divide()'s intended behavior when b == 0?

Several possible ways for divide() to handle divide-by-zero:

A) does not handle division-by-zero. (Callers must ensure b != 0)

int divide( int a, int b )
{
assert( b != 0 );
...

B) throws exception

int divide( int a, int b )
{
if ( b == 0 )
throw std::invalid_argument("divide by zero");
...

C) evaluates to 0 (emulates PowerPC behavior)

int divide( int a, int b )
{
if (b == 0)
return 0;
...

Currently, divide()'s de-facto behavior for division-by-zero is undefined.
But without an assert documenting divide's b != 0 precondition, there is no
way of being certain whether the undefined behavior in this case reflects an
intentional design decision or an accidental oversight.

Greg

 
Reply With Quote
 
SpiralCorp
Guest
Posts: n/a
 
      01-28-2007


On Jan 27, 11:10 pm, BobR <(E-Mail Removed)> wrote:
> SpiralCorp wrote:
>
> >>>What do you guys think, whats the proper way of doing it? >>
> >>It is kosher and is a fine way to return multiple values from a

>
> >>function. Another way is to define a struct that contains multiple
> >>values, and use the struct as the function's return.
> >>- - >>Scott McPhillips [VC++ MVP]

>
> > Good to know. I'll keep using the reference method as I'm not so
> > familiar with structs yet, but I'll make a note for when I am. Thanks
> > for the help.
> > ---
> > SpiralCorp'struct' and 'class' are very useful tools. I'll give you a short example:

>
> #include <iostream>
>
> struct Thing{ // same as "class Thing{ public:"
> int Num;
> char Ch;
> }; // note semicolon at end
>
> void Func( Thing &Th ){
> Th.Num = 42;
> Th.Ch = 'Z';
> return;
> }
>
> int main(){
> Thing Mine;
> Func( Mine );
> std::cout<<"Mine: Num="<<Mine.Num<<" Ch="
> <<Mine.Ch<<std::endl;
>
> int A( Mine.Num );
> char B( Mine.Ch );
> std::cout<<"int A="<<A<<" char B="<<B<<std::endl;
>
> return 0;
> }
>
> That's only the very tip of the iceberg. <G>
> Bob R
> POVrookie



Indeed they are. I'm reading up on them now. And man this group is
responsive, its nice to see so many useful answers.

By the way, to everyone correcting the code up there it was just a
random example for regular use of the return statement. It was copied
from cplusplus.com's tutorial on functions.

>Though this is still annoyingly verbose. This seems like something the
>language should take care of for me. Something like:
>
>[T1, T2] fn()
>{
> return [T1(), T2()] ;
>
>}
>
>int main()
>{
> [T1 a, T2 b] = fn() ;
>
>}
>
>--
>Alan Johnson.


Heh, this is exactly what I was trying to do. It really should be a
language feature in my opinion, its a very reasonable situation.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Small cameras getting too small? GRL Digital Photography 50 02-03-2006 03:12 AM
Small Square with small red X Peter Coddington Computer Support 4 01-03-2006 06:58 AM
what value does lack of return or empty "return;" return Greenhorn C Programming 15 03-06-2005 08:19 PM
How do I return a return-code from main? wl Java 2 03-05-2004 05:15 PM
Return a return value from Perl to Javascript PvdK Perl 0 07-24-2003 09:20 AM



Advertisments