Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid out parameters?

I've seen numerous arguments that using a return value is preferable to out parameters. I am convinced of the reasons why to avoid them, but I find myself unsure if I'm running into cases where it is unavoidable.

Part One of my question is: What are some of your favorite/common ways of getting around using an out parameter? Stuff along the lines: Man, in peer reviews I always see other programmers do this when they could have easily done it this way.

Part Two of my question deals with some specific cases I've encountered where I would like to avoid an out parameter but cannot think of a clean way to do so.

Example 1: I have a class with an expensive copy that I would like to avoid. Work can be done on the object and this builds up the object to be expensive to copy. The work to build up the data is not exactly trivial either. Currently, I will pass this object into a function that will modify the state of the object. This to me is preferable to new'ing the object internal to the worker function and returning it back, as it allows me to keep things on the stack.

class ExpensiveCopy //Defines some interface I can't change.
{
public:
    ExpensiveCopy(const ExpensiveCopy toCopy){ /*Ouch! This hurts.*/ };
    ExpensiveCopy& operator=(const ExpensiveCopy& toCopy){/*Ouch! This hurts.*/};

    void addToData(SomeData);
    SomeData getData();
}

class B
{
public:
    static void doWork(ExpensiveCopy& ec_out, int someParam);
    //or
    // Your Function Here.
}

Using my function, I get calling code like this:

const int SOME_PARAM = 5;
ExpensiveCopy toModify;
B::doWork(toModify, SOME_PARAM);

I'd like to have something like this:

ExpensiveCopy theResult = B::doWork(SOME_PARAM);

But I don't know if this is possible.

Second Example: I have an array of objects. The objects in the array are a complex type, and I need to do work on each element, work that I'd like to keep separated from the main loop that accesses each element. The code currently looks like this:

std::vector<ComplexType> theCollection;
for(int index = 0; index < theCollection.size(); ++index)
{
    doWork(theCollection[index]);
}

void doWork(ComplexType& ct_out)
{
   //Do work on the individual element.
}

Any suggestions on how to deal with some of these situations? I work primarily in C++, but I'm interested to see if other languages facilitate an easier setup. I have encountered RVO as a possible solution, but I need to read up more on it and it sounds like a compiler specific feature.

like image 419
FP. Avatar asked Jan 26 '10 16:01

FP.


1 Answers

I'm not sure why you're trying to avoid passing references here. It's pretty much these situations that pass-by-reference semantics exist.

The code

static void doWork(ExpensiveCopy& ec_out, int someParam);

looks perfectly fine to me.

If you really want to modify it then you've got a couple of options

  1. Move doWork so that's it's a member of ExpensiveCopy (which you say you can't do, so that's out)
  2. return a (smart) pointer from doWork instead of copying it. (which you don't want to do as you want to keep things on the stack)
  3. Rely on RVO (which others have pointed out is supported by pretty much all modern compilers)
like image 116
Glen Avatar answered Sep 17 '22 14:09

Glen