Discussion:
[bind] Help with functional composition of shared_ptr::use_count in std::map
Hughes, James
2007-06-11 11:03:47 UTC
Permalink
Hello all,

I'm trying to use bind to help with removeif in a std::map<string,
shared_ptr<something> >. I want to remove items where the shared_ptr
use_count is 1.

map<string, shared_ptr<data> > Fred;

RemoveIf(Fred.begin(),
Fred.end(),
boost::bind(std::equal_to<long>(),
1,
boost::bind(&map<string, shared_ptr<data>
::value_type::second::use_count, _1)
)

However, I get a compile error on ::second not being a class or
namespace.

Anyone know how I should do this? I'm a beginner at boost::bind, so be
gentle....

James

This message (including any attachments) contains confidential
and/or proprietary information intended only for the addressee.
Any unauthorized disclosure, copying, distribution or reliance on
the contents of this information is strictly prohibited and may
constitute a violation of law. If you are not the intended
recipient, please notify the sender immediately by responding to
this e-mail, and delete the message from your system. If you
have any questions about this e-mail please notify the sender
immediately.
Hughes, James
2007-06-11 11:15:20 UTC
Permalink
-----Original Message-----
Hughes, James
Sent: 11 June 2007 12:04
Subject: [Boost-users] [bind] Help with functional
composition ofshared_ptr::use_count in std::map
Hello all,
I'm trying to use bind to help with removeif in a
std::map<string, shared_ptr<something> >. I want to remove
items where the shared_ptr use_count is 1.
map<string, shared_ptr<data> > Fred;
RemoveIf(Fred.begin(),
Fred.end(),
boost::bind(std::equal_to<long>(),
1,
boost::bind(&map<string, shared_ptr<data>
::value_type::second::use_count, _1)
)
However, I get a compile error on ::second not being a class
or namespace.
Anyone know how I should do this? I'm a beginner at
boost::bind, so be gentle....
James
Sorry, that should read remove_if, and in fact the purpose is better
served using shared_ptr<>::unique, which should mean I can get rid of
the std:equal_to stuff

RemoveIf(Fred.begin(),
Fred.end(),
boost::bind(&map<string, shared_ptr<data>
::value_type::second::unique, _1)
)

Still get same compile fault however.

James

This message (including any attachments) contains confidential
and/or proprietary information intended only for the addressee.
Any unauthorized disclosure, copying, distribution or reliance on
the contents of this information is strictly prohibited and may
constitute a violation of law. If you are not the intended
recipient, please notify the sender immediately by responding to
this e-mail, and delete the message from your system. If you
have any questions about this e-mail please notify the sender
immediately.
Hughes, James
2007-06-11 11:42:24 UTC
Permalink
Post by Hughes, James
Post by Hughes, James
Hello all,
I'm trying to use bind to help with removeif in a std::map<string,
shared_ptr<something> >. I want to remove items where the
shared_ptr
Post by Hughes, James
use_count is 1.
map<string, shared_ptr<data> > Fred;
RemoveIf(Fred.begin(),
Fred.end(),
boost::bind(std::equal_to<long>(),
1,
boost::bind(&map<string, shared_ptr<data>
::value_type::second::use_count, _1)
)
However, I get a compile error on ::second not being a class or
namespace.
Anyone know how I should do this? I'm a beginner at
boost::bind, so be
Post by Hughes, James
gentle....
James
Sorry, that should read remove_if, and in fact the purpose is
better served using shared_ptr<>::unique, which should mean I
can get rid of the std:equal_to stuff
RemoveIf(Fred.begin(),
Fred.end(),
boost::bind(&map<string, shared_ptr<data>
Post by Hughes, James
::value_type::second::unique, _1)
)
Still get same compile fault however.
James
Have now replaced second in above with second_type

Remove_if(Fred.begin(),
Fred.end(),
boost::bind(&map<string, shared_ptr<data>
Post by Hughes, James
::value_type::second_type::unique, _1)
)

And am not getting a completely differnet error - bind seems to be doing
a load of work, but eventually I get an

mem_fn_template.hpp:90: error : No matching function for call to
'get_pointer(const std::pair<const std::string, boost::shared_ptr<data>
Post by Hughes, James
&)'
I'm running out of ideas here so all welcome..

James

This message (including any attachments) contains confidential
and/or proprietary information intended only for the addressee.
Any unauthorized disclosure, copying, distribution or reliance on
the contents of this information is strictly prohibited and may
constitute a violation of law. If you are not the intended
recipient, please notify the sender immediately by responding to
this e-mail, and delete the message from your system. If you
have any questions about this e-mail please notify the sender
immediately.
Peter Dimov
2007-06-11 13:11:15 UTC
Permalink
Post by Hughes, James
RemoveIf(Fred.begin(),
Fred.end(),
boost::bind(&map<string, shared_ptr<data>
::value_type::second::unique, _1)
)
Still get same compile fault however.
It would be nice if this could work with a single bind, but unfortunately
you need two:

boost::bind( &shared_ptr<data>::unique,
boost::bind( &map<string, shared_ptr<data> >::value_type::second, _1 )
)

There is an additional pitfall here; depending on the version of boost::bind
and the compiler, the inner bind may return a shared_ptr by value, making
the use_count at least 2. You should probably just fall back to the
old-fashioned

bool second_unique( map<string, shared_ptr<data> >::value_type & v )
{
return v.second.unique();
}

(I'm using a non-const reference as a parameter to guard against potential
silent implicit conversions which could also increase the use_count.)

Removing the unique entries sounds like purging a cache, maybe weak_ptr will
work better in your map?
Hughes, James
2007-06-11 13:26:20 UTC
Permalink
-----Original Message-----
Sent: 11 June 2007 14:11
Subject: Re: [Boost-users] [bind] Help with
functionalcompositionofshared_ptr::use_count in std::map
Post by Hughes, James
RemoveIf(Fred.begin(),
Fred.end(),
boost::bind(&map<string, shared_ptr<data>
::value_type::second::unique, _1)
)
Still get same compile fault however.
It would be nice if this could work with a single bind, but
boost::bind( &shared_ptr<data>::unique,
boost::bind( &map<string, shared_ptr<data>
Post by Hughes, James
::value_type::second, _1 )
)
There is an additional pitfall here; depending on the version
of boost::bind and the compiler, the inner bind may return a
shared_ptr by value, making the use_count at least 2. You
should probably just fall back to the old-fashioned
bool second_unique( map<string, shared_ptr<data> >::value_type & v ) {
return v.second.unique();
}
(I'm using a non-const reference as a parameter to guard
against potential silent implicit conversions which could
also increase the use_count.)
Removing the unique entries sounds like purging a cache,
maybe weak_ptr will work better in your map?
Thanks Peter - you are right - it's a cache!

James

This message (including any attachments) contains confidential
and/or proprietary information intended only for the addressee.
Any unauthorized disclosure, copying, distribution or reliance on
the contents of this information is strictly prohibited and may
constitute a violation of law. If you are not the intended
recipient, please notify the sender immediately by responding to
this e-mail, and delete the message from your system. If you
have any questions about this e-mail please notify the sender
immediately.

Küppers, Ben
2007-06-11 12:17:19 UTC
Permalink
Post by Hughes, James
map<string, shared_ptr<data> > Fred;
RemoveIf(Fred.begin(),
Fred.end(),
boost::bind(&map<string, shared_ptr<data>
::value_type::second::unique, _1)
)
James,

remove_if requires an assignment operator on the operated type but the value_type of a map is defined as std::pair< const T1, T2 >. The const on the first type will cause any assignment to fail. In other words, you can't use remove_if on a map.

That said, in order to fix your bind you would need two functors. The type passed to the bind is the value_type of the map which is by definition a pair. You need to first invoke a functor on the pair to extract the second member and then call the member unique on the resulting smart pointer. In order to do so you'll need to write your own extractor, because the STL does not provide a functor to obtain the "second" field from a pair (I haven't found one in boost either).

template< class Pair >
struct second_of : std::unary_function< Pair, typename Pair:second_type > {
typename Pair::second_type opertator()( const Pair& the_pair ) const {
return the_pair.second;
}
};

std::for_each(
Fred.begin(),
Fred.end(),
boost::bind(
boost::shared_ptr< data >::unique,
boost::bind(
second_of< std::map< std::string, boost::shared_ptr< data > >::value_type >(), _1 ) ) );

Note that you can call for_each as it does not require the assignment operator.

Hope this helps,

Ben


This e-mail and any attachment is for authorised use by the intended recipient(s) only. It may contain proprietary material, confidential information and/or be subject to legal privilege. It should not be copied, disclosed to, retained or used by, any other party. If you are not an intended recipient then please promptly delete this e-mail and any attachment and all copies and inform the sender. Thank you.
Hughes, James
2007-06-11 13:20:03 UTC
Permalink
-----Original Message-----
Sent: 11 June 2007 13:17
Subject: Re: [Boost-users] [bind] Help with
functionalcompositionofshared_ptr::use_count in std::map
Post by Hughes, James
map<string, shared_ptr<data> > Fred;
RemoveIf(Fred.begin(),
Fred.end(),
boost::bind(&map<string, shared_ptr<data>
::value_type::second::unique, _1)
)
James,
remove_if requires an assignment operator on the operated
type but the value_type of a map is defined as std::pair<
const T1, T2 >. The const on the first type will cause any
assignment to fail. In other words, you can't use remove_if on a map.
That said, in order to fix your bind you would need two
functors. The type passed to the bind is the value_type of
the map which is by definition a pair. You need to first
invoke a functor on the pair to extract the second member and
then call the member unique on the resulting smart pointer.
In order to do so you'll need to write your own extractor,
because the STL does not provide a functor to obtain the
"second" field from a pair (I haven't found one in boost either).
template< class Pair >
struct second_of : std::unary_function< Pair, typename
Pair:second_type > {
typename Pair::second_type opertator()( const Pair&
the_pair ) const {
return the_pair.second;
}
};
std::for_each(
Fred.begin(),
Fred.end(),
boost::bind(
boost::shared_ptr< data >::unique,
boost::bind(
second_of< std::map< std::string, boost::shared_ptr<
data > >::value_type >(), _1 ) ) );
Note that you can call for_each as it does not require the
assignment operator.
Hope this helps,
Ben
Thanks Ben,

That explains the problems. As it turns out, I reckon that the following, which completely avoids any bind stuff, is easier to read and understand...its a pity I chose such a dodgy example as a first bind effort!!!!


typedef std::map< std::string, boost::shared_ptr<data> > cachetype;

cachetype Cache; // and add some stuff to it

cachetype::iterator pos;

for (pos = Cache.begin(); pos != Cache.end();)
{
if (pos->second.unique())
Cache.erase(pos++);
else
++pos;
}

See page 205 in The C++ Standard Library by Josuttis for reasoning.

James

This message (including any attachments) contains confidential
and/or proprietary information intended only for the addressee.
Any unauthorized disclosure, copying, distribution or reliance on
the contents of this information is strictly prohibited and may
constitute a violation of law. If you are not the intended
recipient, please notify the sender immediately by responding to
this e-mail, and delete the message from your system. If you
have any questions about this e-mail please notify the sender
immediately.
Loading...