
Aleksey Gurtovoy <agurtovoy@meta-comm.com> writes:
It became way too easy to write an innocently looking transformation that in fact invokes undefined behavior -- and the latter is not even diagnosed by the most compilers (neither at compile nor at run time). Consider, for instance, this:
#include <boost/iterator/transform_iterator.hpp> #include <boost/bind.hpp> #include <algorithm>
struct X { X( int i = 7 ) : i_( i ) {} ~X() { this->i_ = -1; } int const& get_i() const { return this->i_; }
private: int i_; };
struct Y { X x; }; X make_x( int i ) { return X( i ); }
int main() { int i[] = { 8 }; Y y[1];
// undefined behavior #1 (returning reference to a temporary) int r = *boost::make_transform_iterator( boost::make_transform_iterator( i, std::ptr_fun( &make_x ) ) , std::mem_fun_ref( &X::get_i ) );
assert( r == 8 );
// undefined behavior #2 (returning reference to a temporary) r = *boost::make_transform_iterator( boost::make_transform_iterator( y, boost::bind( &Y::x, _1 ) ) , std::mem_fun_ref( &X::get_i ) );
assert( r == 7 ); }
IMO this is way too subtle and error-prone to leave it as is. Opinions?
Well I'm afraid there's too much going on in that code for me to see where the problems are without some narrative. You could take that as an argument that it's too subtle, but personally I would never write something that involved and "just expect it to work," so I don't see it that way. Maybe you could add some commentary? -- Dave Abrahams Boost Consulting www.boost-consulting.com