Boost logo

Boost :

From: Lewis Hyatt (lhyatt_at_[hidden])
Date: 2007-07-05 17:05:33


I'm not quite sure I understand the behavior of this simple test of
BOOST_FOREACH:

-------------
#include <vector>
#include <iostream>
#include <boost/foreach.hpp>
using namespace std;

struct noisy_vector : public vector<int> {
        explicit noisy_vector(size_t const sz=0, int const val=0) :
vector<int>(sz, val) {
                cerr << "\tcontainer was constructed" << endl;
        }
        noisy_vector(noisy_vector const& other) : vector<int>(other) {
                cerr << "\tcontainer was copied" << endl;
        }
        noisy_vector& operator=(noisy_vector const& other) {
                vector<int>::operator=(other);
                cerr << "\tcontainer was assigned" << endl;
        }
        ~noisy_vector() {
                cerr << "\tcontainer was destructed" << endl;
        }
};

inline noisy_vector get_vec(size_t const sz, int const val=0) {
        return noisy_vector(sz,val);
}

int main() {
        cerr << "TEST 1: LVALUE" << endl;
        {
                noisy_vector vec = get_vec(5);
                cerr << "\tstarting foreach" << endl;
                BOOST_FOREACH(int const& i, vec);
        }
        cerr << endl;
        
        cerr << "TEST2: LVALUE, REFERENCE" << endl;
        {
                noisy_vector const& vec = get_vec(5);
                cerr << "\tstarting foreach" << endl;
                BOOST_FOREACH(int const& i, vec);
        }
        
        cerr << "TEST 2: RVALUE" << endl;
        {
                cerr << "\tstarting foreach" << endl;
                BOOST_FOREACH(int const& i, get_vec(5));
        }
        
}

-------------

If I compile this, using g++ 3.4.4, with the RVO disabled (using
-fno-elide-constructors), then I get the following output:

-------------
TEST 1: LVALUE
         container was constructed
         container was copied
         container was destructed
         container was copied
         container was destructed
         starting foreach
         container was destructed

TEST2: LVALUE, REFERENCE
         container was constructed
         container was copied
         container was destructed
         starting foreach
         container was destructed
TEST 2: RVALUE
         starting foreach
         container was constructed
         container was copied
         container was destructed
         container was copied
         container was copied
         container was destructed
         container was destructed
         container was destructed

-------------

If I compile it with the RVO enabled, I get the following output:
-------------
TEST 1: LVALUE
         container was constructed
         starting foreach
         container was destructed

TEST2: LVALUE, REFERENCE
         container was constructed
         starting foreach
         container was destructed
TEST 2: RVALUE
         starting foreach
         container was constructed
         container was copied
         container was destructed
         container was destructed
-------------

So in either case, using BOOST_FOREACH requires one extra copy. Why is
this necessary? I guess the macro is making a copy of the argument to
avoid evaluating it more than once, but isn't it possible just to bind
the temporary to a const reference instead?

Thanks...

-Lewis


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk