[bind] Surprising behavior

Hi there, I'm sure it's not a bug in bind but I have found a surprising behavior when using it. In my project I have to use some old school c++ classes that use character arrays instead of std::string. The following code displays a difference when using two ways of printing those character arrays. #include <iostream> #include <string> #include <vector> #include <algorithm> #include <functional> #include <boost/bind.hpp> using namespace std; using namespace boost; class A { public: A( string name ) { strncpy( _name, name.c_str(), name.length() + 1 ); } string name() const { return _name; } private: char _name[80]; }; void print( const char* s ) { cout << s << endl; } int main(int argc, char* argv[]) { vector<A> as; as.push_back( A( "A" )); as.push_back( A( "B" )); for_each( as.begin() , as.end() , bind( &print , bind( &std::string::c_str , bind( &A::name, _1 )))); vector<A>::const_iterator it = as.begin(); vector<A>::const_iterator end = as.end(); for( ; it != end; ++it ) { cout << it->name() << endl; } return 0; } The output should be A B A B But instead it's A B The foreach loop doesn't print anything. The problem is when calling the print function the char* points to an empty string. Can somebody please enlightening, here. Thanks, Christian

Christian Henning wrote:
for_each( as.begin() , as.end() , bind( &print , bind( &std::string::c_str , bind( &A::name, _1 ))));
The problem here is that A::name returns a temporary std::string; the code is similar to char const * s = it->name().c_str(); print( s ); Since the temporary std::string is destroyed, s remains dangling. One way of avoiding the problem is to make print() take a std::string instead of a char*.

Thanks Peter, this makes sense. But just image I cannot change the print function's interface. For example I have to interface with MFC's CComboBox::AddString( LPCTSTR lpszString ) . Do you think there is still a way to have just one for_each() loop? My guts tell me no. Thanks again, Christian On 4/16/07, Peter Dimov <pdimov@mmltd.net> wrote:
Christian Henning wrote:
for_each( as.begin() , as.end() , bind( &print , bind( &std::string::c_str , bind( &A::name, _1 ))));
The problem here is that A::name returns a temporary std::string; the code is similar to
char const * s = it->name().c_str(); print( s );
Since the temporary std::string is destroyed, s remains dangling. One way of avoiding the problem is to make print() take a std::string instead of a char*.
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Christian Henning wrote:
Thanks Peter, this makes sense. But just image I cannot change the print function's interface. For example I have to interface with MFC's CComboBox::AddString( LPCTSTR lpszString ) . Do you think there is still a way to have just one for_each() loop? My guts tell me no.
Not without writing your own wrapper function void print2( std::string const & s ) { print( s.c_str() ); } and binding that instead of 'print'.

boost-users-bounces@lists.boost.org, le :
Thanks Peter, this makes sense. But just image I cannot change the print function's interface. For example I have to interface with MFC's CComboBox::AddString( LPCTSTR lpszString ) . Do you think there is still a way to have just one for_each() loop? My guts tell me no.
A while ago, I posted a very similar question, which was not answered: http://groups.google.ca/group/boost-list/browse_thread/thread/c24afb8e21 26fc88/b372145c0385d381?lnk=st&q=emalenfant+boost&rnum=1&hl=fr#b372145c0 385d381. In there, I was asking for comments about 2 workarounds which, adapted to your case would be: 1) var_type<std::string>::type temp(var(std::string())); std::for_each( begin, end, ( temp = bind(&A::name, _1), bind(Print, bind(&std::string::c_str, temp)) ) ); 2) var_type<std::string>::type temp(var(std::string())); std::for_each( begin, end, bind(Print, bind(&std::string::c_str, (temp = bind(&A::name, _1)) ) ) ); Note that this is more "for fun" than, anything. None of these is very elegant, or efficient...

Eric MALENFANT wrote:
2) var_type<std::string>::type temp(var(std::string()));
std::for_each( begin, end, bind(Print, bind(&std::string::c_str, (temp = bind(&A::name, _1)) ) ) );
Note that this is more "for fun" than, anything.
In the "for fun" spirit, here's the boost::bind equivalent: string& (string::*assign)( string const & ) = &string::operator=; std::for_each( begin, end, bind( Print, bind( &std::string::c_str, bind( assign, string(), bind( &A::name, _1 ) ) ) ) );
participants (3)
-
Christian Henning
-
Eric MALENFANT
-
Peter Dimov