Burgeoning Move Semantics Library

I have to stop playing with this stuff and get back to work now, but over the weekend I started a library that allows a "reasonably convenient, useful amount" of move semantics. Many compilers implement enough (N)RVO that implicit moving from rvalues is unneccessary, and those seem to coincide roughly with the compilers where we have to internally shut off some capability because of the compiler's interpretation of 8.5.3/5 (**). So it seems you can pretty much eliminate all needless copies. Here's what you can do with the current state of the move library, which supplies macros (eeeeew!) to avoid code duplication: struct X : boost::movable<X> { BOOST_LVALUE_COPY_CTOR( X, (rhs)(: initializers...), { // copy ctor body }) BOOST_LVALUE_ASSIGN( X, (rhs), { // copy assign body }) X(move_from<X> rhs) { // move ctor logic } X& operator=(move_from<X> rhs) { // move assign logic } }; boost::movable<X> just encapsulates the conversion to move_from<X> and makes the copy ctor/assignment private, so you can always replace it with a written-out conversion to move_from<X> if you don't like the "MI non-EBO" (or other) impact of library-mandated inheritance. This work owes inspiration to Rani Sharoni's "improved auto_ptr" (http://tinyurl.com/2rxpj) and of course one must acknowledge Andrei Alexandrescu for being crazy enough to even try doing this in a library in the first place (Mojo). Eric Friedman had an earlier boost/move.hpp in the sandbox based on Mojo (which I replaced with his permission), and I adapted his tests, in addition to my own, to work with the new code. It might make sense to use this library to optimize selected Boost components; shared_ptr, any, and dynamic_bitset come to mind, just off the top of my head. You can find the code in boost/move.hpp and tests in libs/move/test/*.cpp. It "basically works" with all MSVC versions, Borland, gcc-2.95, gcc-3.3.1, comeau (strict warnings mode only, until I find out how to detect that we're in strict errors mode), and all intel-win32 versions. I don't know how to make gcc-3.2 work yet. The places where it fails, certain things seem to compile which one would prefer to cause an error. Enjoy, Dave (**) see http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2004/n1610.html -- Dave Abrahams Boost Consulting www.boost-consulting.com

Hi, I'm just wondering if the deafening silence indicates a lack of interest or whether something else is going on? Feedback would be appreciated. Thanks! David Abrahams <dave@boost-consulting.com> writes:
I have to stop playing with this stuff and get back to work now, but over the weekend I started a library that allows a "reasonably convenient, useful amount" of move semantics. Many compilers implement enough (N)RVO that implicit moving from rvalues is unneccessary, and those seem to coincide roughly with the compilers where we have to internally shut off some capability because of the compiler's interpretation of 8.5.3/5 (**). So it seems you can pretty much eliminate all needless copies.
Here's what you can do with the current state of the move library, which supplies macros (eeeeew!) to avoid code duplication:
struct X : boost::movable<X> { BOOST_LVALUE_COPY_CTOR( X, (rhs)(: initializers...), { // copy ctor body })
BOOST_LVALUE_ASSIGN( X, (rhs), { // copy assign body })
X(move_from<X> rhs) { // move ctor logic }
X& operator=(move_from<X> rhs) { // move assign logic } };
boost::movable<X> just encapsulates the conversion to move_from<X> and makes the copy ctor/assignment private, so you can always replace it with a written-out conversion to move_from<X> if you don't like the "MI non-EBO" (or other) impact of library-mandated inheritance.
This work owes inspiration to Rani Sharoni's "improved auto_ptr" (http://tinyurl.com/2rxpj) and of course one must acknowledge Andrei Alexandrescu for being crazy enough to even try doing this in a library in the first place (Mojo). Eric Friedman had an earlier boost/move.hpp in the sandbox based on Mojo (which I replaced with his permission), and I adapted his tests, in addition to my own, to work with the new code.
It might make sense to use this library to optimize selected Boost components; shared_ptr, any, and dynamic_bitset come to mind, just off the top of my head.
You can find the code in boost/move.hpp and tests in libs/move/test/*.cpp. It "basically works" with all MSVC versions, Borland, gcc-2.95, gcc-3.3.1, comeau (strict warnings mode only, until I find out how to detect that we're in strict errors mode), and all intel-win32 versions. I don't know how to make gcc-3.2 work yet. The places where it fails, certain things seem to compile which one would prefer to cause an error.
Enjoy, Dave
(**) see http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2004/n1610.html -- Dave Abrahams Boost Consulting www.boost-consulting.com
-- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams ha escrito:
Hi,
I'm just wondering if the deafening silence indicates a lack of interest or whether something else is going on? Feedback would be appreciated.
I've got move semantics supports in the roadmap for my indexed_set (likely to be renamed multi_index_container) library, so your code can be (for me at least) of great value. Quick questions: * Seems like your library does not support the temporary return part (I mean, the equivalent of mojo::fnresult). Is this right? If so, are you planning to add support for this part as well? * In those classes with fast swap, is this a right approach to implement the move constructor? X(move_from<X> rhs) { this.swap(rhs); } Best, Joaquín M López Muñoz Telefónica, Investigación y Desarrollo

Joaquín Mª López Muñoz <joaquin@tid.es> writes:
David Abrahams ha escrito:
Hi,
I'm just wondering if the deafening silence indicates a lack of interest or whether something else is going on? Feedback would be appreciated.
I've got move semantics supports in the roadmap for my indexed_set (likely to be renamed multi_index_container) library, so your code can be (for me at least) of great value.
Great!
Quick questions:
* Seems like your library does not support the temporary return part (I mean, the equivalent of mojo::fnresult). Is this right? If so, are you planning to add support for this part as well?
I don't know what you mean. That hack is unneccessary with my library. It's non-intrusive on clients of the movable class (unless they explicitly want to distinguish rvalue from const lvalue arguments for moving purposes). To return a movable class rvalue efficiently, you just return it. Try the move.cpp test with --verbose-test on GCC to see what I mean.
* In those classes with fast swap, is this a right approach to implement the move constructor?
X(move_from<X> rhs) { this.swap(rhs); }
Not usually; that will default-initialize all bases and members before doing the swap. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams ha escrito:
Joaquín Mª López Muñoz <joaquin@tid.es> writes:
[...]
Quick questions:
* Seems like your library does not support the temporary return part (I mean, the equivalent of mojo::fnresult). Is this right? If so, are you planning to add support for this part as well?
I don't know what you mean. That hack is unneccessary with my library. It's non-intrusive on clients of the movable class (unless they explicitly want to distinguish rvalue from const lvalue arguments for moving purposes). To return a movable class rvalue efficiently, you just return it.
Ok, I must be misunderstanding your comment about VRO. So, what does this mean? "Many compilers implement enough (N)RVO that implicit moving from" "rvalues is unneccessary"
Try the move.cpp test with --verbose-test on GCC to see what I mean.
* In those classes with fast swap, is this a right approach to implement the move constructor?
X(move_from<X> rhs) { this.swap(rhs); }
Not usually; that will default-initialize all bases and members before doing the swap.
Yep, but I'm thinking about a container, where initializing to an empy sequence is insignificant compared to copying the whole elements of rhs. In the particular case of multi_indexed_container, if this approach works it would achieve move semantics by adding about 20 lines of a code to a single class (multi_index_container): indices proper wouldn't have to care about move semantics at all. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo

Joaquín Mª López Muñoz <joaquin@tid.es> writes:
Ok, I must be misunderstanding your comment about VRO. So, what does this mean?
"Many compilers implement enough (N)RVO that implicit moving from" "rvalues is unneccessary"
The point of my library is to provide: 1. a uniform way for callees to detect rvalue arguments (use move_from<X> as an argument and make the lvalue overload templated with enable_if_same) 2. a uniform way to declare that an lvalue argument may be moved from (pass it as move(x)). 3. Allow classes to be written that automatically use move semantics when rvalues would ordinarily be copied, as in when an object is returned from a function (provide a constructor accepting move_from<X> and a conversion to move_from<X> or inherit from movable<X>). That's what I mean by "implicit moving from rvalues". 4. Provide a simple way to declare the constructor and assignment operator overloads needed to make movable classes also copyable (BOOST_LVALUE_COPY_CTOR and BOOST_LVALUE_ASSIGN). Compilers that implement both URVO and NRVO seem to never copy an rvalue anyway, so they don't need part 3 except in order to explicit moving of lvalues.
Try the move.cpp test with --verbose-test on GCC to see what I mean.
* In those classes with fast swap, is this a right approach to implement the move constructor?
X(move_from<X> rhs) { this.swap(rhs); }
Not usually; that will default-initialize all bases and members before doing the swap.
Yep, but I'm thinking about a container, where initializing to an empy sequence is insignificant compared to copying the whole elements of rhs.
In that case, yes, that would be an appropriate move constructor. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
Hi,
I'm just wondering if the deafening silence indicates a lack of interest or whether something else is going on? Feedback would be appreciated.
I'm interested. And from what I can tell, the implementation looks good. The macros are cool, even though my syntax highlighting broke down completely when I used them. ;) -- Daniel Wallin

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Daniel Wallin Sent: Wednesday, April 14, 2004 9:40 AM To: boost@lists.boost.org Subject: [boost] Re: Yo, move semantics anyone?
David Abrahams wrote:
Hi,
I'm just wondering if the deafening silence indicates a lack of interest or whether something else is going on? Feedback would be appreciated.
I'm interested. And from what I can tell, the implementation looks good. The macros are cool, even though my syntax highlighting broke down completely when I used them. ;)
I'm interested in it, as well. Probably a lot of us figure it's better to just lurk if we don't have anything of earth-shattering importance. OT, though, out of professional curiousity, what editor did this break the syntax highlighting in? Reid

David Abrahams wrote:
I'm just wondering if the deafening silence indicates a lack of interest or whether something else is going on?
The latter. Thanks for your efforts, I for my part will definitely have a closer look on it when time allows. BTW, what was the result of the proposal on clarification of this? S.

David Abrahams wrote:
Hi,
I'm just wondering if the deafening silence indicates a lack of interest or whether something else is going on? Feedback would be appreciated.
Dave, I'd like to try using this in the auto_new class I mentioned a while back: http://aspn.activestate.com/ASPN/Mail/Message/1862884 The code in boost-sandbox/libs/move/test/move_test.cpp, especially at line 162 containing: moveable_string sink(source()); looks like what I'd like to do with auto_new only instead of a moveable_string sink aond source(), there would be something like: smart_ptr<T,cyclic_ref_count<_> > sink(auto_new(T,a0,a1,...,an)); However, I haven't had time to investigate your code to see if I could use it for this purpose. As it is, I've "rolled my own" variation of the auto_ptr and auto_ptr_ref classes to handle the problem, but I'm having a lot of trouble getting smart_ptr::release and smart_ptr::reset to work. I'll be happy to post the code if you want to see what you can do; however, I'll have to warn you that the code will take some time to decipher.

Larry Evans wrote: [snip]
a moveable_string sink aond source(), there would be something like:
smart_ptr<T,cyclic_ref_count<_> > sink(auto_new(T,a0,a1,...,an));
OOPS. auto_new(...) Should be: auto_new<T,cyclic_ref_count<_>::overhead_type>(a0,a1,..,an)
participants (6)
-
Daniel Wallin
-
David Abrahams
-
Joaquín Mª López Muñoz
-
Larry Evans
-
Reid Sweatman
-
Stefan Slapeta