views:

323

answers:

4

Hi,

I've recently started using boost lambda and thought I'd try and use it in places where it will/should make things easier to read.

I have some code similar to the following

std::vector< X * > v;
for ( int i = 0 ; i < 20 ; ++i )
    v.push_back( new X() );

and later on, to delete it...

std::for_each( v.begin(), v.end(), boost::lamda::delete_ptr() );

Which neatly tidies up.

However, I thought I'd have a go at "lambda-ising" the population of the vector using lambda... That's then the fireworks started...

I tried..

std::generate_n( v.begin(), 20, _1 = new X() );

but this threw all kinds of compiler errors.

Any ideas which is the best "lambda" way to achieve this.

Thx Mark.

A: 

Can't help you with lambda, but have you looked at boost::assign library?

Nikolai N Fetissov
No, but I'll check it out right now.
ScaryAardvark
A: 

Ok, After an extra bit of playing I came up with this...

std::generate_n( std::back_insert_iterator< std::vector< X* > >( ip ), 20, new_ptr< X >() ) );

I'm not quite sure this is as elegant. From a programming perspective, it may be, but from a "in-6-months-time-will-I-know-what-this-was-meant-to-do" perspectice, I'm not sure...

Feel free to point out better ways of doing this.

ScaryAardvark
At least std::back_inserter(v) makes it a little more readable.
stefaanv
std::back_inserter's template target is a type not an instance so unfortunately it has to be std::vector< X * >, not v
ScaryAardvark
back_inserter is a function so it can automatically deduce the tempalte argument - see my answer below.
Joe Gauterin
Ah. sorry, I missed the fact it was a function. Good thinking :o)
ScaryAardvark
+4  A: 

You might consider:

static const int PtrVectorSize = 20;

// ....
v.resize(PtrVectorSize);
generate_n(v.begin(), PtrVectorSize, new_ptr<X>());

Also, you could use boost::ptr_vector and save your self the deletes.

Todd Gardner
Yes, that's certainly more legible. I like the way you've got rid of the back_inserter by resizing..
ScaryAardvark
It is most likely a little more efficient to do a reserve or a resize prior to filling the generate, and I normally favor the resize/iterator over the reserve/back_inserter for sequences of a known size, though I suppose the second one could be considered "safer" in an exceptional sense.
Todd Gardner
+9  A: 

Here's a code snippet that does what you want:

#include <algorithm>
#include <vector>

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/construct.hpp>

typedef int X;

int main() {
  std::vector<X*> v;
  std::generate_n( std::back_inserter(v), 20, boost::lambda::new_ptr<X>() );
  std::for_each( v.begin(), v.end(), boost::lambda::delete_ptr() );
}

You might want to consider using boost::ptr_vector though, as using a std::vector with dynamically allocated pointers in an exception safe way isn't easy.

Joe Gauterin
Alternatively: I would suspect the following version to be slightly more efficient `std::vector<X*> v(20,0);` `std::for_each(v.begin(), v.end(), boost::lambda::new_ptr<X>());` because only one memory allocation is triggered for the vector while yours may trigger a reallocation during `std::generate_n`.
Matthieu M.
If you wanted to achieve that you could just stick a v.reserve(20) infront of the generate_n call.
Joe Gauterin