stl and standard library functions

S

sks_cpp

I am somewhat new to STL and the plethora of library functions they have. I
looked at sgi's stl info. and I was overwhelmed so I thought I would present
my question here.

I have
std::map<WWN*, Drive*> m_Drives

I want to take that and run a functor through all of them (the functor has
Drive* has the parameter type) and whichever ones meet the predicate functor
will need to be added to a list of Drive*s. (std::list<Drive*> driveList)

I can write a loop to do this and in fact, I will do it here to show what I
am trying to achieve. But I would rather use the library functions, if
possible.

for ( mapIter i = m_Drives.begin(); i != m_Drives.end(); ++i )
{
if ( i.second->getType == someType && i.second->getCapacity >=
someCapacity )
driveList.push_back(i.second);
}

My code may not compile since I just wrote it on the fly.
My for loop is only few lines long so maybe doing that is better than using
the standard library functions.

However, I read part of Scott Meyers's Effective STL stuff and he says that
standard functions are efficient, correct, and maintainable. Anyway, any
help would be nice.

Thanks.
 
?

=?iso-8859-1?Q?Juli=E1n?= Albo

sks_cpp escribió:
I have
std::map<WWN*, Drive*> m_Drives

I want to take that and run a functor through all of them (the functor has
Drive* has the parameter type) and whichever ones meet the predicate functor
will need to be added to a list of Drive*s. (std::list<Drive*> driveList)

I can write a loop to do this and in fact, I will do it here to show what I
am trying to achieve. But I would rather use the library functions, if
possible.

for ( mapIter i = m_Drives.begin(); i != m_Drives.end(); ++i )
{
if ( i.second->getType == someType && i.second->getCapacity >=
someCapacity )
driveList.push_back(i.second);
}

Something like that (untested):

class SelectDrive {
public:
SelectDrive (std::list <Drive *> & driveList, Type type, int capacity)
:
driveList (driveList), type (type), capacity (capacity)
{ }
void operator () (const std::map <WWN *, Drive *>::value_type & i)
{
if (i.second->getType == someType && i.second->getCapacity >=
capacity)
driveList.push_back (i.second);
}
private:
std::list <Drive *> & driveList;
Type type;
int capacity;
};

An use as:

std::for_each (m_Drives.begin (), m_Drives.end (),
SelectDrive (driveList, someType, someCapacity) );

Regards.
 
J

Jerry Coffin

I am somewhat new to STL and the plethora of library functions they have. I
looked at sgi's stl info. and I was overwhelmed so I thought I would present
my question here.

I have
std::map<WWN*, Drive*> m_Drives

I want to take that and run a functor through all of them (the functor has
Drive* has the parameter type) and whichever ones meet the predicate functor
will need to be added to a list of Drive*s. (std::list<Drive*> driveList)

std::remove_copy_if seems to be what you're looking for. Using this
you'll have to reverse the sense of your predicate -- it copies
elements, removing those for which the predicate is true, rather than
only copying those for which it is true.

// warning: untested code.
bool your_predicate(std::pair<WWN*, Drive *> p) {
return (p.second->getType != someType ||
p.second->getCapacity < someCapacity);
}

std::remove_copy_if(m_drives.begin(), m_drives.end(),
std::inserter(driveList, driveList.end()),
your_predicate);

Please don't ask me why the committee preferred remove_copy_if to
copy_if -- I have no idea, and mostly disagree. At least to me, the
name std::remove_copy_if sounds like it should be a variant of
std::unique, or something on that order, but it's basically just the
(unfortunately nonexistent) std::copy_if having a really bad hair day.
 
S

sks_cpp

std::remove_copy_if(m_drives.begin(), m_drives.end(),
std::inserter(driveList, driveList.end()),
your_predicate);

I don't want to remove from the map - just insert the ones that meet the
criteria into the list. Is that what the above code does? What does inserter
do?
Please don't ask me why the committee preferred remove_copy_if to
copy_if -- I have no idea, and mostly disagree. At least to me, the
name std::remove_copy_if sounds like it should be a variant of
std::unique, or something on that order, but it's basically just the
(unfortunately nonexistent) std::copy_if having a really bad hair day.

I might have to agree with you here.

Thanks for your suggestions/comments.
 
S

sks_cpp

Julián Albo said:
class SelectDrive {
public:
SelectDrive (std::list <Drive *> & driveList, Type type, int capacity)
:
driveList (driveList), type (type), capacity (capacity)
{ }
void operator () (const std::map <WWN *, Drive *>::value_type & i)
{
if (i.second->getType == someType && i.second->getCapacity >=
capacity)
driveList.push_back (i.second);
}
private:
std::list <Drive *> & driveList;
Type type;
int capacity;
};

Thanks for your coments. I found something interesting with your operator
method. It takes "value_type" as its parameter. Now, could it have taken a
pair? What if you overload the operators with ambiguous parameters, such as
"value_type" as you have it and "pair<WWN*, Drive*>" - is that a compiler
error or does one have precedence over the other?

Thanks.
 
J

Jerry Coffin

I don't want to remove from the map - just insert the ones that meet the
criteria into the list.

That's part of what I meant about remove_copy_if having a deceiving
name. It leaves the contents of the original container unaffected. It
just removes the items from the copy -- which is to say that if they
meet the criteria, it doesn't copy them.
Is that what the above code does? What does inserter do?

Yes. std::inserter is just a utility function that creates an
insert_iterator for a particular spot in a particular container. In
case you're not familiar with insert_iterators (and
back_insert_iterators, etc.) they're iterators that insert items into a
collection -- i.e. they don't just overwrite items at locations, but
create space for new ones. e.g. with something like this:

std::vector x, y;

for(int i=0; i<10; ++i)
x.push_back(i);

std::copy(x.begin(), x.end(), back_inserter(y, y.end());

the back_inserter creates an iterator that basically does a push_back to
put each item into y. This saves you from having to resize y to the
correct size ahead of time, which would be trivial in the situation
above, but much more difficult in a situation like yours, where you
don't know ahead of time how many items you'll be inserting into the
list.
 
J

Jerry Coffin

[ ... ]
std::copy(x.begin(), x.end(), back_inserter(y, y.end());

Oops -- with back_inserter, you don't need to specify an iterator, since
it always inserts at the back. I.e. the call above should be just:

std::copy(x.begin(), x.end(), back_inserter(y));

with std::inserter, you have to specify an iterator as the point where
the insertion(s) will take place, since (unlike back_inserter) it's not
implicit.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top