tags:

views:

101

answers:

5

Hi!

I would like to do something like this (I'm aware that this won't compile):

struct Container{
    vector<int> storage;
};

float foo(Container* aContainer){
    if(aContainer!=NULL)
        vector<int>& workingStorage=aContainer->storage;
    else
        vector<int> workingStorage; 


    workingStorage.reserve(1000000);
    ....use workingStorage to calculate something......

    return calculated_result;
}

So - if i pass a Container to the function, i want that the function uses the vector in the container to work with instead of a local variable. If no container is provided, it should use a local variable.

of course I could just in the end of the function copy the local variable to the storage of the Container, but that's not what I want to do.

Thanks!

+14  A: 

Create a local std::vector<int> named local_storage for the case where a container is not provided by the caller, then create a reference to whatever container you are actually going to use.

std::vector<int> local_storage;

std::vector<int>& working_storage = aContainer 
                                        ? aContainer->storage 
                                        : local_storage;
James McNellis
+1: I was going to suggest using a pointer, as this is one use case where references don't cut it (they are not variables). But I really like this solution :-)
André Caron
@James: You rightly pointed out on my (now deleted) answer that you can't bind a reference to a temporary variable. But doesn't the ternary expression in your code also evaluate to a temporary variable?
Oli Charlesworth
@Oli: No; that's why I create `local_storage` first; it always gets created regardless of whether it is used.
James McNellis
@James: I realise that, but how does the reference bind "through" the ternary operator?
Oli Charlesworth
exactly what I need - so obvious! thanks! =)
Mat
just curious - could this also be achieved using if-else instead of ? operator?
Mat
@Oli: Oh, I see what you mean now. No; if I recall correctly, if both of the branches of the conditional operator are lvalue expressions, the conditional expression itself is an lvalue expression. I don't recall all the exact details off the top of my head, but it's something to that effect.
James McNellis
@Mat: No; since a reference must be bound to an object when it is initialized and you can't rebind a reference, you must use the conditional operator for this. You could use a pointer if you wanted, but in my opinion this way using a reference is _much_ cleaner than using a pointer.
James McNellis
Oli Charlesworth
@Oli: Informally and to the best of my recollection, yes. This also allows the conditional operator to be used on the left hand side, as in `(expr ? a : b) = T()`.
James McNellis
@James: Well, +1 for providing me with the thing I learnt today!
Oli Charlesworth
@Oli: The "formal" phrasing is: "If the second and third operands are lvalues and have the same type, the result is of that type and is an lvalue" (C++03 5.16/4).
James McNellis
+1  A: 
vector<int> temp;
vector<int>& workingStorage = (aContainer!=NULL) ? aContainer->storage : temp;
A: 

Why don't you make sure that aContainer->storage is initialized before you pass aContainer it to foo. That makes your code lot more neater. Have an assert statement at the start of the function to check aContainer->storage for NULL.

Ravi Gummadi
because I do not want to enforce having to provide a container.
Mat
+3  A: 

One way to approach this problem is to break the function foo into 2 functions

float foo(Container* aContainer){ 
  if(aContainer!=NULL) {
    return foo_core(aContainer->storage);
  } else { 
    vector<int> workingStorage;  
    return foo_core(workingStorage);
}

float foo_core(vector<int>& workingStorage) { 
  ... 
  // rest of original foo
}
JaredPar
+1 no as nifty as James' but it makes up for it with its clarity.
Matthieu M.
+1  A: 

The design is apparently horrible. But given that an optional externally provided storage is what you want, JaredPar (his answer) has a good idea. Cleaning that further up:

struct Container
{
    vector<int> storage;
};

double foo( vector<int>& workingStorage )
{
    workingStorage.reserve( 1000000 );
    //....use workingStorage to calculate something......
    return calculated_result;
}

double foo( Container& storageProvider )
{
    return foo( storageProvider.storage );
}

double foo()
{
    vector<int> storage;
    return foo( storage );
}

Cheers & hth.,

Alf P. Steinbach