Jamie Cook
Jamie Cook

Reputation: 4545

BOOST_FOREACH implicit use of reference?

I am wondering if there is any benefit to getting a reference to a vector prior to calling BOOST_FOREACH or whether a method call which returns a reference will be automatically used? For example which of the two following loops will be equivalent to the third loop?

vector<float>& my_method();

void main()
{
    // LOOP 1 -------------------------------
    vector<float>& temp_vector = my_method();
    BOOST_FOREACH(float element, temp_vector)
        cout << element << endl;

    // LOOP 2 -------------------------------
    vector<float> temp_vector = my_method();
    BOOST_FOREACH(float element, temp_vector)
        cout << element << endl;

    // Which loop is this one most like? ----
    BOOST_FOREACH(float element, my_method())
        cout << element << endl;
}

Upvotes: 3

Views: 2394

Answers (3)

Alex B
Alex B

Reputation: 84972

Looking through BOOST_FOREACH metaprogramming madness I see that the collection gets copied if it's

  1. an rvalue,
  2. a "lightweight proxy", which you can define for your types by specializing boost::foreach::is_lightweight_proxy.

Hence, lvalue is not copied. Instead, its pointer is taken as a temporary.

Crucial bit is this:

# define BOOST_FOREACH_SHOULD_COPY(COL)             \
     (true ? 0 : boost::foreach_detail_::or_(       \
         BOOST_FOREACH_IS_RVALUE(COL)               \
       , BOOST_FOREACH_IS_LIGHTWEIGHT_PROXY(COL)))

Then it's used as one of the arguments to the function that is used to evaluate a container into a temporary variable:

template<typename T> 
inline auto_any<T> contain(T const &t, boost::mpl::true_ *) // rvalue 
{ 
    return t;
}

template<typename T>
inline auto_any<T *> contain(T &t, boost::mpl::false_ *) // lvalue
{
    // Cannot seem to get sunpro to handle addressof() with array types.
    #if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x570))
    return &t;
    #else
    return boost::addressof(t);
    #endif
}

I have Boost v1.38 installed in my system.

Upvotes: 2

visitor
visitor

Reputation: 8834

A quick test shows that the function is called once and no copying occurs in connection with BOOST_FOREACH.

#include <vector>
#include <iostream>
#include <boost/foreach.hpp>

struct X
{
    X() {}
    X(const X& ) { std::cout << "copied\n"; }
};

std::vector<X> vec(2);

//std::vector<X> method()
std::vector<X>& method()
{
    std::cout << "returning from method\n";
    return vec;
}

int main()
{
    BOOST_FOREACH(const X& x, method()) {}
}

Upvotes: 4

f4.
f4.

Reputation: 3852

And although BOOST_FOREACH is a macro, it is a remarkably well-behaved one. It evaluates its arguments exactly once, leading to no nasty surprises

so my_method() won't be called more than once

References behaves like "normal" variables from the user point of view, you can treat the reference exactly as if it were the original variable. It makes no difference to the foreach loop.

So both loops are equivalent.

Upvotes: 0

Related Questions