views:

244

answers:

10

I have a local that's only used for the purposes of checking the result from another function and passing it on if it meets certain criteria. Most of the time, that criteria will never be met. Is there any way I can avoid this "extra" local?

I only have about 1MB of storage for my binary, and I have several thousand function calls that follow this pattern. I know it's a minor thing, but if there's a better pattern I'd love to know!

SomeDataType myclass::myFunction()
{
   SomeDataType result;  // do I really need this local???

   // i need to check the result and pass it on if it meets a certain condition
   result = doSomething();
   if ( ! result ) {
      return result;
   }

   // do other things here
   ...

   // normal result of processing
   return SomeDataType(whatever);
}
+5  A: 

How complex is SomeDataType? Does it have a lot of members? Does it do a lot of work in a constructor? If so, then I'd avoid this. If not, you may find the compiler will generate good code for this. For example, the compiler will probably do pretty well with integer types.

With a question like this, the answer is almost always: consult the compiler's assembly output.

asveikau
In my case SomeDataType is a very simple concrete (non-virtual) class with a single integer member variable and about a dozen member functions. The constructor performs an assignment only. I know with a fair amount of certainty its cheaper to create it as a return value on the stack than as a local whenever I can. However, I'd really like a general solution if one exists as I can't guarantee SomeDataType will always be that.
Well, I for one don't think there is a good general solution for this. In fact problems like this one makes my C++ very very "C like" when I code for platforms with tight memory-constraints.
S.C. Madsen
I agree, you should take a look at the assembly that your compiler generates. If this variable can fit in a register, any good embedded compiler should have optimized it away for you.
bta
A: 

As asveikau pointed out, if SomeDataType will "fit in a register" (i.g. its a plain old int), then your local will (depending on the platform) not waste any memory. And I concur with asveikau that you should consult the assembly output to evaluate if this is the case.

S.C. Madsen
+1  A: 

Depends if your compiler has return value opitmization or not, and if Somedatatype is big or small. The safe side is using smart pointers for this kind of patterns if objects are big. If they are POD, they might be optimized and returned on registers.

piotr
+1  A: 

What if change function to

void myclass::myFunction(SomeDataType* pResult)
{
  // i need to check the result and pass it on if it meets a certain condition
   *pResult = doSomething();
   if ( ! *pResult ) {
      return;
   }

   // do other things here
   ...

   // normal result of processing
  *pResult = SomeDataType(whatever);
}
drlazy
A modern compiler can already do this. Look up RVO.
MSalters
Hmm. Perhaps the right direction, but I'm not sure. I just tried a quick compiler test, and adding the extra parameter to the function call seemed to consume the exact same amount of space as the local, but I'm not sure that's right as I may not have hit the minimum exe size with such a small test.
don't forget about operation occurs when returning an object from function, it actually including creation of temporary object, return value is assigned to abject, than if you assing result of function to variable assgn operator is performed, if you are not assigning, but use somthing like myFunction().doSomething() there will be no assignment, but typical usage in most cases is var = myFunction()
drlazy
RVO: Good call, but there's a lot of caveats with that to depend on it with certainty. Good article I just found on Dr. Dobbs on the topic: http://www.drdobbs.com/cpp/184403855Aaargh. I'm really trying to avoid two versions of the executable just to find which is better, but I guess I really should know better and just check the output eh? Ce'est la vie.
+1  A: 

If you're not using the result variable elsewhere in the function you could try this:

if (!doSomething())
{
    return;
}

The above example allows the compiler to create temporary variables if necessary, rather that you telling the compiler to create one.

If you are a stickler for structured programming, you could try this:

do
{
    if (!doSomething())
    {
        break;
    }
// ...
} while (false);
return;

This example allows for only one return point in a function. Which may be a good thing when dealing with quality and traceability guidelines.

Thomas Matthews
A: 

If you have a pattern that repeats in thousands of functions, you could consider replacing it with one function and a look-up table.

(I can't really be more specific without knowing more details about your situation.)

Craig McQueen
+1  A: 

I would disassemble the code and figure out what your compiler is doing when it generates the code. Modern compilers do some tricky stuff, and trying to guess how to save code space is not obvious - sometimes I see very little correspondence from the source to the assembly. Source code is more about clarity and maintenance - generating the assembly has different metrics.

Jeff
A: 

I'd suggest that you check your compiler options and make sure that they are set to "optimize for size" since that is what you're worried about. And if your compiler doesn't have something like this as a setting, then perhaps it's time to check out a different one.

jamesv
A: 

In your call to doSomething(), instead of returning null, you could return SomeDataType(whatever).

ajs410
A: 

I would suggest you don't worry about it. It's not really a good use of time to optimize down at this level, since any decent compiler will minimize the amount of the local storage required. The stack is reusable, thousands of calls won't matter because the memory is only required for the context where it is used and will not be relevant beyond that.

If it is really necessary for you to be concerned about a few bytes of temporary storage on the stack, you should probably be working in assembly. I doubt this is the case, so don't sweat it and spend your time on other more interesting and important issues!

reese.ch