Index: function_base.hpp =================================================================== --- function_base.hpp (revision 45260) +++ function_base.hpp (working copy) @@ -122,7 +122,7 @@ union function_buffer { // For pointers to function objects - void* obj_ptr; + mutable void* obj_ptr; // For pointers to std::type_info objects // (get_functor_type_tag, check_functor_type_tag). @@ -203,9 +203,11 @@ template struct reference_manager { + // Note: the 4th argument (bool) would specify whether to move the buffer, + // but this is irrelevant in this case. static inline void get(const function_buffer& in_buffer, function_buffer& out_buffer, - functor_manager_operation_type op) + functor_manager_operation_type op, bool) { switch (op) { case clone_functor_tag: @@ -319,17 +321,21 @@ typedef Functor functor_type; // Function pointers + // Note: the 5th argument (bool) would specify whether to move the buffer, + // but this is irrelevant for function pointers. static inline void manager(const function_buffer& in_buffer, function_buffer& out_buffer, - functor_manager_operation_type op, function_ptr_tag) + functor_manager_operation_type op, function_ptr_tag, bool) { functor_manager_common::manage_ptr(in_buffer,out_buffer,op); } // Function objects that fit in the small-object buffer. + // Note: the 5th argument (bool) would specify whether to move the buffer, + // but this is irrelevant when the small-object buffer is used. static inline void manager(const function_buffer& in_buffer, function_buffer& out_buffer, - functor_manager_operation_type op, mpl::true_) + functor_manager_operation_type op, mpl::true_, bool) { functor_manager_common::manage_small(in_buffer,out_buffer,op); } @@ -337,16 +343,24 @@ // Function objects that require heap allocation static inline void manager(const function_buffer& in_buffer, function_buffer& out_buffer, - functor_manager_operation_type op, mpl::false_) + functor_manager_operation_type op, mpl::false_, bool move_buffer) { if (op == clone_functor_tag) { - // Clone the functor - // GCC 2.95.3 gets the CV qualifiers wrong here, so we - // can't do the static_cast that we should do. - const functor_type* f = - (const functor_type*)(in_buffer.obj_ptr); - functor_type* new_f = new functor_type(*f); - out_buffer.obj_ptr = new_f; + if (move_buffer) + { + out_buffer.obj_ptr = in_buffer.obj_ptr; + in_buffer.obj_ptr = 0; + } + else + { + // Clone the functor + // GCC 2.95.3 gets the CV qualifiers wrong here, so we + // can't do the static_cast that we should do. + const functor_type* f = + (const functor_type*)(in_buffer.obj_ptr); + functor_type* new_f = new functor_type(*f); + out_buffer.obj_ptr = new_f; + } } else if (op == destroy_functor_tag) { /* Cast from the void pointer to the functor pointer type */ functor_type* f = @@ -368,10 +382,10 @@ // whether we need to allocate it on the heap. static inline void manager(const function_buffer& in_buffer, function_buffer& out_buffer, - functor_manager_operation_type op, function_obj_tag) + functor_manager_operation_type op, function_obj_tag, bool move_buffer) { manager(in_buffer, out_buffer, op, - mpl::bool_<(function_allows_small_object_optimization::value)>()); + mpl::bool_<(function_allows_small_object_optimization::value)>(), move_buffer); } public: @@ -379,7 +393,7 @@ function pointer or a function object pointer. */ static inline void manage(const function_buffer& in_buffer, function_buffer& out_buffer, - functor_manager_operation_type op) + functor_manager_operation_type op, bool move_buffer) { typedef typename get_function_tag::type tag_type; switch (op) { @@ -388,7 +402,7 @@ return; default: - manager(in_buffer, out_buffer, op, tag_type()); + manager(in_buffer, out_buffer, op, tag_type(), move_buffer); return; } } @@ -403,7 +417,7 @@ // Function pointers static inline void manager(const function_buffer& in_buffer, function_buffer& out_buffer, - functor_manager_operation_type op, function_ptr_tag) + functor_manager_operation_type op, function_ptr_tag, bool move_buffer) { functor_manager_common::manage_ptr(in_buffer,out_buffer,op); } @@ -559,7 +573,8 @@ vtable_base() : manager(0) { } void (*manager)(const function_buffer& in_buffer, function_buffer& out_buffer, - functor_manager_operation_type op); + functor_manager_operation_type op, + bool move_buffer); }; } // end namespace function } // end namespace detail @@ -585,7 +600,7 @@ if (!vtable) return typeid(void); detail::function::function_buffer type; - vtable->manager(functor, type, detail::function::get_functor_type_tag); + vtable->manager(functor, type, detail::function::get_functor_type_tag, false); return *static_cast(type.const_obj_ptr); } Index: function_template.hpp =================================================================== --- function_template.hpp (revision 45260) +++ function_template.hpp (working copy) @@ -286,7 +286,7 @@ void clear(function_buffer& functor) { if (manager) - manager(functor, functor, destroy_functor_tag); + manager(functor, functor, destroy_functor_tag, false); } private: @@ -729,9 +729,10 @@ if (&other == this) return; - BOOST_FUNCTION_FUNCTION tmp = *this; - *this = other; - other = tmp; + BOOST_FUNCTION_FUNCTION tmp; + tmp.move_assign(*this); + this->move_assign(other); + other.move_assign(tmp); } // Clear out a target, if there is one @@ -768,10 +769,31 @@ if (!f.empty()) { this->vtable = f.vtable; f.vtable->manager(f.functor, this->functor, - boost::detail::function::clone_functor_tag); + boost::detail::function::clone_functor_tag, false); } } + // Moves the value from the specified argument to *this. If the argument + // has its function object allocated on the heap, move_assign will pass + // its buffer to *this, and set the argument's buffer pointer to NULL. + void move_assign(BOOST_FUNCTION_FUNCTION& f) + { + if (&f == this) + return; + + clear(); + try { + if (!f.empty()) { + this->vtable = f.vtable; + f.vtable->manager(f.functor, this->functor, + boost::detail::function::clone_functor_tag, true); + } + } catch (...) { + vtable = 0; + throw; + } + } + template void assign_to(Functor f) {