123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977 |
- [/
- / Copyright (c) 2008-2010 Ion Gaztanaga
- /
- / Distributed under the Boost Software License, Version 1.0. (See accompanying
- / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- /]
- [library Boost.Move
- [quickbook 1.5]
- [authors [Gaztanaga, Ion]]
- [copyright 2008-2014 Ion Gaztanaga]
- [id move]
- [dirname move]
- [purpose Move semantics]
- [license
- Distributed under the Boost Software License, Version 1.0.
- (See accompanying file LICENSE_1_0.txt or copy at
- [@http://www.boost.org/LICENSE_1_0.txt])
- ]
- ]
- [important To be able to use containers of movable-only values in C++03 mode you will need to use containers
- supporting move semantics, like [*Boost.Container] containers]
- [section:tested_compilers Tested compilers]
- [*Boost.Move] has been tested in the following compilers/platforms:
- * Visual C++ >= 7.1.
- * GCC >= 4.1.
- [warning GCC < 4.3 and MSVC < 9.0 are deprecated and will be removed in the next version.]
- [endsect]
- [section:what_is_boost_move What is Boost.Move?]
- Rvalue references are a major C++0x feature, enabling move semantics for C++ values. However, we
- don't need C++0x compilers to take advantage of move semanatics. [*Boost.Move] emulates C++0x
- move semantics in C++03 compilers and allows writing portable code that works optimally in C++03
- and C++0x compilers.
- [endsect]
- [section:introduction Introduction]
- [note
- The first 3 chapters are the adapted from the article
- [@http://www.artima.com/cppsource/rvalue.html ['A Brief Introduction to Rvalue References]]
- by Howard E. Hinnant, Bjarne Stroustrup, and Bronek Kozicki
- ]
- Copying can be expensive. For example, for vectors `v2=v1` typically involves a function call,
- a memory allocation, and a loop. This is of course acceptable where we actually need two copies of
- a vector, but in many cases, we don't: We often copy a `vector` from one place to another, just to
- proceed to overwrite the old copy. Consider:
- [c++]
- template <class T> void swap(T& a, T& b)
- {
- T tmp(a); // now we have two copies of a
- a = b; // now we have two copies of b
- b = tmp; // now we have two copies of tmp (aka a)
- }
- But, we didn't want to have any copies of a or b, we just wanted to swap them. Let's try again:
- [c++]
- template <class T> void swap(T& a, T& b)
- {
- T tmp(::boost::move(a));
- a = ::boost::move(b);
- b = ::boost::move(tmp);
- }
- This `move()` gives its target the value of its argument, but is not obliged to preserve the value
- of its source. So, for a `vector`, `move()` could reasonably be expected to leave its argument as
- a zero-capacity vector to avoid having to copy all the elements. In other words, [*move is a potentially
- destructive copy].
- In this particular case, we could have optimized swap by a specialization. However, we can't
- specialize every function that copies a large object just before it deletes or overwrites it. That
- would be unmanageable.
- In C++0x, move semantics are implemented with the introduction of rvalue references. They allow us to
- implement `move()` without verbosity or runtime overhead. [*Boost.Move] is a library that offers tools
- to implement those move semantics not only in compilers with `rvalue references` but also in compilers
- conforming to C++03.
- [endsect]
- [section:implementing_movable_classes Implementing copyable and movable classes]
- [import ../example/doc_clone_ptr.cpp]
- [section:copyable_and_movable_cpp0x Copyable and movable classes in C++0x]
- Consider a simple handle class that owns a resource and also provides copy semantics
- (copy constructor and assignment). For example a `clone_ptr` might own a pointer, and call
- `clone()` on it for copying purposes:
- [c++]
- template <class T>
- class clone_ptr
- {
- private:
- T* ptr;
- public:
- // construction
- explicit clone_ptr(T* p = 0) : ptr(p) {}
- // destruction
- ~clone_ptr() { delete ptr; }
- // copy semantics
- clone_ptr(const clone_ptr& p)
- : ptr(p.ptr ? p.ptr->clone() : 0) {}
- clone_ptr& operator=(const clone_ptr& p)
- {
- if (this != &p)
- {
- T *p = p.ptr ? p.ptr->clone() : 0;
- delete ptr;
- ptr = p;
- }
- return *this;
- }
- // move semantics
- clone_ptr(clone_ptr&& p)
- : ptr(p.ptr) { p.ptr = 0; }
- clone_ptr& operator=(clone_ptr&& p)
- {
- if(this != &p)
- {
- std::swap(ptr, p.ptr);
- delete p.ptr;
- p.ptr = 0;
- }
- return *this;
- }
- // Other operations...
- };
- `clone_ptr` has expected copy constructor and assignment semantics, duplicating resources when copying.
- Note that copy constructing or assigning a `clone_ptr` is a relatively expensive operation:
- [copy_clone_ptr]
- `clone_ptr` is code that you might find in today's books on C++, except for the part marked as
- `move semantics`. That part is implemented in terms of C++0x `rvalue references`. You can find
- some good introduction and tutorials on rvalue references in these papers:
- * [@http://www.artima.com/cppsource/rvalue.html ['A Brief Introduction to Rvalue References]]
- * [@http://blogs.msdn.com/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx ['Rvalue References: C++0x Features in VC10, Part 2]]
- When the source of the copy is known to be a `rvalue` (e.g.: a temporary object), one can avoid the
- potentially expensive `clone()` operation by pilfering source's pointer (no one will notice!). The move
- constructor above does exactly that, leaving the rvalue in a default constructed state. The move assignment
- operator simply does the same freeing old resources.
- Now when code tries to copy a rvalue `clone_ptr`, or if that code explicitly gives permission to
- consider the source of the copy a rvalue (using `boost::move`), the operation will execute much faster.
- [move_clone_ptr]
- [endsect]
- [section:copyable_and_movable_cpp03 Copyable and movable classes in portable syntax for both C++03 and C++0x compilers]
- Many aspects of move semantics can be emulated for compilers not supporting `rvalue references`
- and [*Boost.Move] offers tools for that purpose. With [*Boost.Move] we can write `clone_ptr`
- so that it will work both in compilers with rvalue references and those who conform to C++03.
- You just need to follow these simple steps:
- * Put the following macro in the [*private] section:
- [macroref BOOST_COPYABLE_AND_MOVABLE BOOST_COPYABLE_AND_MOVABLE(classname)]
- * Leave copy constructor as is.
- * Write a copy assignment taking the parameter as
- [macroref BOOST_COPY_ASSIGN_REF BOOST_COPY_ASSIGN_REF(classname)]
- * Write a move constructor and a move assignment taking the parameter as
- [macroref BOOST_RV_REF BOOST_RV_REF(classname)]
- Let's see how are applied to `clone_ptr`:
- [clone_ptr_def]
- [endsect]
- [*Question]: What about types that don't own resources? (E.g. `std::complex`?)
- No work needs to be done in that case. The copy constructor is already optimal.
- [endsect]
- [section:composition_inheritance Composition or inheritance]
- For classes made up of other classes (via either composition or inheritance), the move constructor
- and move assignment can be easily coded using the `boost::move` function:
- [clone_ptr_base_derived]
- [important Due to limitations in the emulation code, a cast to `Base &` is needed before moving the base part in the move
- constructor and call Base's move constructor instead of the copy constructor.]
- Each subobject will now be treated individually, calling move to bind to the subobject's move
- constructors and move assignment operators. `Member` has move operations coded (just like
- our earlier `clone_ptr` example) which will completely avoid the tremendously more expensive
- copy operations:
- [clone_ptr_move_derived]
- Note above that the argument x is treated as a lvalue reference. That's why it is necessary to
- say `move(x)` instead of just x when passing down to the base class. This is a key safety feature of move
- semantics designed to prevent accidently moving twice from some named variable. All moves from
- lvalues occur explicitly.
- [endsect]
- [section:movable_only_classes Movable but Non-Copyable Types]
- Some types are not amenable to copy semantics but can still be made movable. For example:
- * `unique_ptr` (non-shared, non-copyable ownership)
- * A type representing a thread of execution
- * A type representing a file descriptor
- By making such types movable (though still non-copyable) their utility is tremendously
- increased. Movable but non-copyable types can be returned by value from factory functions:
- [c++]
- file_descriptor create_file(/* ... */);
- //...
- file_descriptor data_file;
- //...
- data_file = create_file(/* ... */); // No copies!
- In the above example, the underlying file handle is passed from object to object, as long
- as the source `file_descriptor` is a rvalue. At all times, there is still only one underlying file
- handle, and only one `file_descriptor` owns it at a time.
- To write a movable but not copyable type in portable syntax, you need to follow these simple steps:
- * Put the following macro in the [*private] section:
- [macroref BOOST_MOVABLE_BUT_NOT_COPYABLE BOOST_MOVABLE_BUT_NOT_COPYABLE(classname)]
- * Write a move constructor and a move assignment taking the parameter as
- [macroref BOOST_RV_REF BOOST_RV_REF(classname)]
- Here's the definition of `file descriptor` using portable syntax:
- [import ../example/doc_file_descriptor.cpp]
- [file_descriptor_def]
- [/
- /Many standard algorithms benefit from moving elements of the sequence as opposed to
- /copying them. This not only provides better performance (like the improved `swap`
- /implementation described above), but also allows these algorithms to operate on movable
- /but non-copyable types. For example the following code sorts a `vector<unique_ptr<T>>`
- /based on comparing the pointed-to types:
- /
- /[c++]
- /
- / struct indirect_less
- / {
- / template <class T>
- / bool operator()(const T& x, const T& y)
- / {return *x < *y;}
- / };
- / ...
- / std::vector<std::unique_ptr<A>> v;
- / ...
- / std::sort(v.begin(), v.end(), indirect_less());
- /
- /
- /As sort moves the unique_ptr's around, it will use swap (which no longer requires Copyability)
- /or move construction / move assignment. Thus during the entire algorithm, the invariant that
- /each item is owned and referenced by one and only one smart pointer is maintained. If the
- /algorithm were to attempt a copy (say by programming mistake) a compile time error would result.
- /]
- [endsect]
- [section:move_and_containers Containers and move semantics]
- Movable but non-copyable types can be safely inserted into containers and
- movable and copyable types are more efficiently handled if those containers
- internally use move semantics instead of copy semantics.
- If the container needs to "change the location" of an element
- internally (e.g. vector reallocation) it will move the element instead of copying it.
- [*Boost.Container] containers are move-aware so you can write the following:
- [file_descriptor_example]
- [endsect]
- [section:construct_forwarding Constructor Forwarding]
- Consider writing a generic factory function that returns an object for a newly
- constructed generic type. Factory functions such as this are valuable for encapsulating
- and localizing the allocation of resources. Obviously, the factory function must accept
- exactly the same sets of arguments as the constructors of the type of objects constructed:
- [c++]
- template<class T> T* factory_new()
- { return new T(); }
- template<class T> T* factory_new(a1)
- { return new T(a1); }
- template<class T> T* factory_new(a1, a2)
- { return new T(a1, a2); }
- Unfortunately, in C++03 the much bigger issue with this approach is that the N-argument case
- would require 2^N overloads, immediately discounting this as a general solution. Fortunately,
- most constructors take arguments by value, by const-reference or by rvalue reference. If these
- limitations are accepted, the forwarding emulation of a N-argument case requires just N overloads.
- This library makes this emulation easy with the help of `BOOST_FWD_REF` and
- `boost::forward`:
- [import ../example/doc_construct_forward.cpp]
- [construct_forward_example]
- Constructor forwarding comes in handy to implement placement insertion in containers with
- just N overloads if the implementor accepts the limitations of this type of forwarding for
- C++03 compilers. In compilers with rvalue references perfect forwarding is achieved.
- [endsect]
- [section:move_return Implicit Move when returning a local object]
- The C++ standard specifies situations where an implicit move operation is safe and the
- compiler can use it in cases were the (Named) Return Value Optimization) can't be used.
- The typical use case is when a function returns a named (non-temporary) object by value
- and the following code will perfectly compile in C++11:
- [c++]
- //Even if movable can't be copied
- //the compiler will call the move-constructor
- //to generate the return value
- //
- //The compiler can also optimize out the move
- //and directly construct the object 'm'
- movable factory()
- {
- movable tmp;
- m = ...
- //(1) moved instead of copied
- return tmp;
- };
- //Initialize object
- movable m(factory());
- In compilers without rvalue references and some non-conforming compilers (such as Visual C++ 2010/2012)
- the line marked with `(1)` would trigger a compilation error because `movable` can't be copied. Using a explicit
- `::boost::move(tmp)` would workaround this limitation but it would code suboptimal in C++11 compilers
- (as the compile could not use (N)RVO to optimize-away the copy/move).
- [*Boost.Move] offers an additional macro called [macroref BOOST_MOVE_RET BOOST_MOVE_RET] that can be used to
- alleviate this problem obtaining portable move-on-return semantics. Let's use the previously presented
- movable-only `movable` class with classes `copyable` (copy-only type), `copy_movable` (can be copied and moved) and
- `non_copy_movable` (non-copyable and non-movable):
- [import ../example/copymovable.hpp]
- [copy_movable_definition]
- and build a generic factory function that returns a newly constructed value or a reference to an already
- constructed object.
- [import ../example/doc_move_return.cpp]
- [move_return_example]
- [*Caution]: When using this macro in a non-conforming or C++03
- compilers, a move will be performed even if the C++11 standard does not allow it
- (e.g. returning a static variable). The user is responsible for using this macro
- only used to return local objects that met C++11 criteria. E.g.:
- [c++]
- struct foo
- {
- copy_movable operator()() const
- {
- //ERROR! The Standard does not allow implicit move returns when the object to be returned
- //does not met the criteria for elision of a copy operation (such as returning a static member data)
- //In C++03 compilers this will MOVE resources from cm
- //In C++11 compilers this will COPY resources from cm
- //so DON'T use use BOOST_MOVE_RET without care.
- return BOOST_MOVE_RET(copy_movable, cm);
- }
- static copy_movable cm;
- };
- [*Note]: When returning a temporary object `BOOST_MOVE_REF` is not needed as copy ellision rules will work on
- both C++03 and C++11 compilers.
- [c++]
- //Note: no BOOST_MOVE_RET
- movable get_movable()
- { return movable(); }
- copy_movable get_copy_movable()
- { return copy_movable(); }
- copyable get_copyable()
- { return copyable(); }
- [endsect]
- [section:move_iterator Move iterators]
- [c++]
- template<class Iterator>
- class move_iterator;
- template<class It>
- move_iterator<It> make_move_iterator(const It &it);
- [classref boost::move_iterator move_iterator] is an iterator adaptor with the
- same behavior as the underlying iterator
- except that its dereference operator implicitly converts the value returned by the
- underlying iterator's dereference operator to a rvalue reference: `boost::move(*underlying_iterator)`
- It is a read-once iterator, but can have up to random access traversal characteristics.
- `move_iterator` is very useful because some generic algorithms and container insertion functions
- can be called with move iterators to replace copying with moving. For example:
- [import ../example/movable.hpp]
- [movable_definition]
- `movable` objects can be moved from one container to another using move iterators and insertion
- and assignment operations.w
- [import ../example/doc_move_iterator.cpp]
- [move_iterator_example]
- [endsect]
- [section:move_inserters Move inserters]
- Similar to standard insert iterators, it's possible to deal with move insertion in the same way
- as writing into an array. A special kind of iterator adaptors, called move insert iterators, are
- provided with this library. With regular iterator classes,
- [c++]
- while (first != last) *result++ = *first++;
- causes a range [first,last) to be copied into a range starting with result. The same code with
- result being a move insert iterator will move insert corresponding elements into the container.
- This device allows all of the copying algorithms in the library to work in the move insert mode
- instead of the regular overwrite mode. This library offers 3 move insert iterators and their
- helper functions:
- [c++]
- // Note: C models Container
- template <typename C>
- class back_move_insert_iterator;
- template <typename C>
- back_move_insert_iterator<C> back_move_inserter(C& x);
- template <typename C>
- class front_move_insert_iterator;
- template <typename C>
- front_move_insert_iterator<C> front_move_inserter(C& x);
- template <typename C>
- class move_insert_iterator;
- template <typename C>
- move_insert_iterator<C> move_inserter(C& x, typename C::iterator it);
- A move insert iterator is constructed from a container and possibly one of its iterators pointing
- to where insertion takes place if it is neither at the beginning nor at the end of the container.
- Insert iterators satisfy the requirements of output iterators. `operator*` returns the move insert
- iterator itself. The assignment `operator=(T& x)` is defined on insert iterators to allow writing
- into them, it inserts x right before where the insert iterator is pointing. In other words, an
- `insert iterator` is like a cursor pointing into the container where the insertion takes place.
- `back_move_iterator` move inserts elements at the end of a container, `front_insert_iterator`
- move inserts elements at the beginning of a container, and `move_insert_iterator` move inserts
- elements where the iterator points to in a container. `back_move_inserter`, `front_move_inserter`,
- and `move_inserter` are three functions making the insert iterators out of a container. Here's
- an example of how to use them:
- [import ../example/doc_move_inserter.cpp]
- [move_inserter_example]
- [endsect]
- [section:move_algorithms Move algorithms]
- The standard library offers several copy-based algorithms. Some of them, like `std::copy` or
- `std::uninitialized_copy` are basic building blocks for containers and other data structures.
- This library offers move-based functions for those purposes:
- [c++]
- template<typename I, typename O> O move(I, I, O);
- template<typename I, typename O> O move_backward(I, I, O);
- template<typename I, typename F> F uninitialized_move(I, I, F);
- template<typename I, typename F> F uninitialized_copy_or_move(I, I, F);
- The first 3 are move variations of their equivalent copy algorithms, but copy assignment and
- copy construction are replaced with move assignment and construction. The last one has the
- same behaviour as `std::uninitialized_copy` but since several standand library implementations
- don't play very well with `move_iterator`s, this version is a portable version for those
- willing to use move iterators.
- [import ../example/doc_move_algorithms.cpp]
- [move_algorithms_example]
- [endsect]
- [section:emulation_limitations Emulation limitations]
- Like any emulation effort, the library has some limitations users should take in
- care to achieve portable and efficient code when using the library with C++03 conformant compilers:
- [section:emulation_limitations_base Initializing base classes]
- When initializing base classes in move constructors, users must
- cast the reference to a base class reference before moving it or just
- use `BOOST_MOVE_BASE`. Example:
- [c++]
- Derived(BOOST_RV_REF(Derived) x) // Move ctor
- : Base(boost::move(static_cast<Base&>(x)))
- //...
- or
- [c++]
- Derived(BOOST_RV_REF(Derived) x) // Move ctor
- : Base(BOOST_MOVE_BASE(Base, x))
- //...
- If casting is not performed the emulation will not move construct
- the base class, because no conversion is available from `BOOST_RV_REF(Derived)` to
- `BOOST_RV_REF(Base)`. Without the cast or `BOOST_MOVE_BASE` we might obtain a compilation
- error (for non-copyable types) or a less-efficient move constructor (for copyable types):
- [c++]
- //If Derived is copyable, then Base is copy-constructed.
- //If not, a compilation error is issued
- Derived(BOOST_RV_REF(Derived) x) // Move ctor
- : Base(boost::move(x))
- //...
- [endsect]
- [section:template_parameters Template parameters for perfect forwarding]
- The emulation can't deal with C++0x reference collapsing rules that allow perfect forwarding:
- [c++]
-
- //C++0x
- template<class T>
- void forward_function(T &&t)
- { inner_function(std::forward<T>(t); }
- //Wrong C++03 emulation
- template<class T>
- void forward_function(BOOST_RV_REF<T> t)
- { inner_function(boost::forward<T>(t); }
- In C++03 emulation BOOST_RV_REF doesn't catch any const rlvalues. For more details on
- forwarding see [link move.construct_forwarding Constructor Forwarding] chapter.
- [endsect]
- [section:emulation_limitations_binding Binding of rvalue references to lvalues]
- The
- [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html first rvalue reference]
- proposal allowed the binding of rvalue references to lvalues:
- [c++]
- func(Type &&t);
- //....
-
- Type t; //Allowed
- func(t)
- Later, as explained in
- [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2812.html ['Fixing a Safety Problem with Rvalue References]]
- this behaviour was considered dangerous and eliminated this binding so that rvalue references adhere to the
- principle of type-safe overloading: ['Every function must be type-safe in isolation, without regard to how it has been overloaded]
- [*Boost.Move] can't emulate this type-safe overloading principle for C++03 compilers:
- [c++]
- //Allowed by move emulation
- movable m;
- BOOST_RV_REF(movable) r = m;
- [endsect]
- [section:assignment_operator Assignment operator in classes derived from or holding copyable and movable types]
- The macro [macroref BOOST_COPYABLE_AND_MOVABLE BOOST_COPYABLE_AND_MOVABLE] needs to
- define a copy constructor for `copyable_and_movable` taking a non-const parameter in C++03 compilers:
- [c++]
- //Generated by BOOST_COPYABLE_AND_MOVABLE
- copyable_and_movable &operator=(copyable_and_movable&){/**/}
- Since the non-const overload of the copy constructor is generated, compiler-generated
- assignment operators for classes containing `copyable_and_movable`
- will get the non-const copy constructor overload, which will surely surprise users:
- [c++]
- class holder
- {
- copyable_and_movable c;
- };
- void func(const holder& h)
- {
- holder copy_h(h); //<--- ERROR: can't convert 'const holder&' to 'holder&'
- //Compiler-generated copy constructor is non-const:
- // holder& operator(holder &)
- //!!!
- }
- This limitation forces the user to define a const version of the copy assignment,
- in all classes holding copyable and movable classes which might be annoying in some cases.
- An alternative is to implement a single `operator =()` for copyable and movable classes
- [@http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ using "pass by value" semantics]:
- [c++]
- T& operator=(T x) // x is a copy of the source; hard work already done
- {
- swap(*this, x); // trade our resources for x's
- return *this; // our (old) resources get destroyed with x
- }
- However, "pass by value" is not optimal for classes (like containers, strings, etc.) that reuse resources
- (like previously allocated memory) when x is assigned from a lvalue.
- [endsect]
- [section:templated_assignment_operator Templated assignment operator in copyable and movable types]
- [import ../example/doc_template_assign.cpp]
- Given a movable and copyable class, if a templated assignment operator (*) is added:
- [template_assign_example_foo_bar]
- C++98 and C++11 compilers will behave different when assigning from a `[const] Foo` lvalue:
- [template_assign_example_main]
- This different behaviour is a side-effect of the move emulation that can't be easily avoided by
- [*Boost.Move]. One workaround is to SFINAE-out the templated assignment operator with `disable_if`:
- [c++]
- template<class U> // Modified templated assignment
- typename boost::disable_if<boost::is_same<U, Foo>, Foo&>::type
- operator=(const U& rhs)
- { i = -rhs.i; return *this; } //(2)
- [endsect]
- [endsect]
- [section:how_the_library_works How the library works]
- [*Boost.Move] is based on macros that are expanded to true rvalue references in C++0x compilers
- and emulated rvalue reference classes and conversion operators in C++03 compilers.
- In C++03 compilers [*Boost.Move] defines a class named `::boost::rv`:
- [c++]
- template <class T>
- class rv : public T
- {
- rv();
- ~rv();
- rv(rv const&);
- void operator=(rv const&);
- };
- which is convertible to the movable base class (usual C++ derived to base conversion). When users mark
- their classes as [macroref BOOST_MOVABLE_BUT_NOT_COPYABLE BOOST_MOVABLE_BUT_NOT_COPYABLE] or
- [macroref BOOST_COPYABLE_AND_MOVABLE BOOST_COPYABLE_AND_MOVABLE], these macros define conversion
- operators to references to `::boost::rv`:
- [c++]
- #define BOOST_MOVABLE_BUT_NOT_COPYABLE(TYPE)\
- public:\
- operator ::boost::rv<TYPE>&() \
- { return *static_cast< ::boost::rv<TYPE>* >(this); }\
- operator const ::boost::rv<TYPE>&() const \
- { return static_cast<const ::boost::rv<TYPE>* >(this); }\
- private:\
- //More stuff...
- [macroref BOOST_MOVABLE_BUT_NOT_COPYABLE BOOST_MOVABLE_BUT_NOT_COPYABLE] also declares a
- private copy constructor and assignment. [macroref BOOST_COPYABLE_AND_MOVABLE BOOST_COPYABLE_AND_MOVABLE]
- defines a non-const copy constructor `TYPE &operator=(TYPE&)` that forwards to a const version:
- #define BOOST_COPYABLE_AND_MOVABLE(TYPE)\
- public:\
- TYPE& operator=(TYPE &t)\
- { this->operator=(static_cast<const ::boost::rv<TYPE> &>(const_cast<const TYPE &>(t))); return *this;}\
- //More stuff...
- In C++0x compilers `BOOST_COPYABLE_AND_MOVABLE` expands to nothing and `BOOST_MOVABLE_BUT_NOT_COPYABLE`
- declares copy constructor and assigment operator private.
- When users define the [macroref BOOST_RV_REF BOOST_RV_REF] overload of a copy constructor/assignment, in
- C++0x compilers it is expanded to a rvalue reference (`T&&`) overload and in C++03 compilers it is expanded
- to a `::boost::rv<T> &` overload:
- [c++]
- #define BOOST_RV_REF(TYPE) ::boost::rv< TYPE >& \
- When users define the [macroref BOOST_COPY_ASSIGN_REF BOOST_COPY_ASSIGN_REF] overload,
- it is expanded to a usual copy assignment (`const T &`) overload in C++0x compilers and
- to a `const ::boost::rv &` overload in C++03 compilers:
- [c++]
- #define BOOST_COPY_ASSIGN_REF(TYPE) const ::boost::rv< TYPE >&
-
- As seen, in [*Boost.Move] generates efficient and clean code for C++0x move
- semantics, without modifying any resolution overload. For C++03 compilers
- when overload resolution is performed these are the bindings:
- * a) non-const rvalues (e.g.: temporaries), bind to `::boost::rv< TYPE >&`
- * b) const rvalue and lvalues, bind to `const ::boost::rv< TYPE >&`
- * c) non-const lvalues (e.g. non-const references) bind to `TYPE&`
- The library does not define the equivalent of
- [macroref BOOST_COPY_ASSIGN_REF BOOST_COPY_ASSIGN_REF] for copy construction (say, `BOOST_COPY_CTOR_REF`)
- because nearly all modern compilers implement RVO and this is much more efficient than any move emulation.
- [funcref boost::move move] just casts `TYPE &` into `::boost::rv<TYPE> &`.
- Here's an example that demostrates how different rlvalue objects bind to `::boost::rv` references in the
- presence of three overloads and the conversion operators in C++03 compilers:
- [import ../example/doc_how_works.cpp]
- [how_works_example]
- [endsect]
- [section:thanks_to Thanks and credits]
- Thanks to all that developed ideas for move emulation: the first emulation was based on Howard Hinnant
- emulation code for `unique_ptr`, David Abrahams suggested the use of `class rv`,
- and Klaus Triendl discovered how to bind const rlvalues using `class rv`.
- Many thanks to all boosters that have tested, reviewed and improved the library.
- Special thanks to:
- * Orson Peters, author of [@https://github.com/orlp/pdqsort Pattern-defeating quicksort (pdqsort)].
- * Andrey Astrelin, author of [@https://github.com/Mrrl/GrailSort Grail Sort].
- [endsect]
- [section:release_notes Release Notes]
- [section:release_notes_boost_1_71 Boost 1.71 Release]
- * Fixed bugs:
- * [@https://github.com/boostorg/move/issues/26 Git Issue #26: ['"Invalid iterator increment/decrement in the last iteration of adaptive_sort_combine_blocks"]].
- [endsect]
- [section:release_notes_boost_1_70 Boost 1.70 Release]
- * Removed support for deprecated GCC compilers.
- * Fixed bugs:
- * [@https://github.com/boostorg/move/pull/23 Git Pull #23: ['"Add minimal cmake file"]].
- * [@https://github.com/boostorg/move/issues/25 Git Issue #25: ['"adaptive_merge is broken for iterator_traits<RandIt>::size_type != std::size_t"]].
- [endsect]
- [section:release_notes_boost_1_69 Boost 1.69 Release]
- * Deprecated GCC < 4.3 and MSVC < 9.0 (Visual 2008) compilers.
- * Fixed bugs:
- * [@https://github.com/boostorg/move/issues/15 Git Issue #19: ['"Compilation error with IBM xlC++ on AIX"]].
- [endsect]
- [section:release_notes_boost_1_67 Boost 1.67 Release]
- * Added pdqsort and heap_sort implementations, initially as a detail, they will be official in the future once better tested.
- [endsect]
- [section:release_notes_boost_1_66 Boost 1.66 Release]
- * Fixed bugs:
- * [@https://github.com/boostorg/move/pull/14 Git Pull #14: ['"Workaround for bogus [-Wignored-attributes] warning on GCC 6.x/7.x"]].
- * [@https://github.com/boostorg/move/issues/15 Git Issue #15: ['"Incorrect merge in adaptive_merge when the number of unique items is limited"]].
- [endsect]
- [section:release_notes_boost_1_65 Boost 1.65 Release]
- * Fixed bug:
- * [@https://github.com/boostorg/move/pull/11 Git Pull #11: ['"replace 'std::random_shuffle' by '::random_shuffle'"]].
- * [@https://github.com/boostorg/move/pull/12 Git Pull #12: ['"Adds support for MSVC ARM64 target'"]].
- [endsect]
- [section:release_notes_boost_1_64 Boost 1.64 Release]
- * Fixed bug:
- * [@https://svn.boost.org/trac/boost/ticket/12920 #12920 ['"movelib::unique_ptr: incorrect pointer type for nested array"]].
- [endsect]
- [section:release_notes_boost_1_62 Boost 1.62 Release]
- * Documented new limitations reported in Trac tickets
- [@https://svn.boost.org/trac/boost/ticket/12194 #12194 ['"Copy assignment on moveable and copyable classes uses wrong type"]] and
- [@https://svn.boost.org/trac/boost/ticket/12307 #12307 ['"Copy assignment from const ref handled differently in C++11/C++98"]].
- [endsect]
- [section:release_notes_boost_1_61 Boost 1.61 Release]
- * Experimental: asymptotically optimal bufferless merge and sort algorithms: [funcref boost::movelib::adaptive_merge adaptive_merge]
- and [funcref boost::movelib::adaptive_sort adaptive_sort].
- * Fixed bug:
- * [@https://svn.boost.org/trac/boost/ticket/11758 Trac #11758: ['"BOOST_MOVABLE_BUT_NOT_COPYABLE doesn't reset private access with rvalue ref version"]],
- [endsect]
- [section:release_notes_boost_1_60 Boost 1.60 Release]
- * Fixed bug:
- * [@https://svn.boost.org/trac/boost/ticket/11615 Trac #11615: ['"Boost.Move should use the qualified name for std::size_t in type_traits.hpp"]],
- [endsect]
- [section:release_notes_boost_1_59 Boost 1.59 Release]
- * Changed `unique_ptr`'s converting constructor taking the source by value in C++03 compilers to allow simple conversions
- from convertible types returned by value.
- * Fixed bug:
- * [@https://svn.boost.org/trac/boost/ticket/11229 Trac #11229: ['"vector incorrectly copies move-only objects using memcpy"]],
- * [@https://svn.boost.org/trac/boost/ticket/11510 Trac #11510: ['"unique_ptr: -Wshadow warning issued"]],
- [endsect]
- [section:release_notes_boost_1_58_00 Boost 1.58 Release]
- * Added [macroref BOOST_MOVE_BASE BOOST_MOVE_BASE] utility.
- * Added [funcref boost::adl_move_swap adl_move_swap] utility.
- * Reduced dependencies on other Boost libraries to make the library a bit more lightweight.
- * Fixed bugs:
- * [@https://svn.boost.org/trac/boost/ticket/11044 Trac #11044: ['"boost::rv inherits off union, when such passed as template argument"]].
- [endsect]
- [section:release_notes_boost_1_57_00 Boost 1.57 Release]
- * Added `unique_ptr` smart pointer. Thanks to Howard Hinnant for his excellent unique_ptr emulation code and testsuite.
- * Added `move_if_noexcept` utility. Thanks to Antony Polukhin for the implementation.
- * Fixed bugs:
- * [@https://svn.boost.org/trac/boost/ticket/9785 Trac #9785: ['"Compiler warning with intel icc in boost/move/core.hpp"]],
- * [@https://svn.boost.org/trac/boost/ticket/10460 Trac #10460: ['"Compiler error due to looser throw specifier"]],
- * [@https://github.com/boostorg/move/pull/3 Git Pull #3: ['"Don't delete copy constructor when rvalue references are disabled"]],
- [endsect]
-
- [section:release_notes_boost_1_56_00 Boost 1.56 Release]
- * Added [macroref BOOST_MOVE_RET BOOST_MOVE_RET].
- * Fixed bugs:
- * [@https://svn.boost.org/trac/boost/ticket/9482 #9482: ['"MSVC macros not undefined in boost/move/detail/config_end.hpp"]],
- * [@https://svn.boost.org/trac/boost/ticket/9045 #9045: ['"Wrong macro name on docs"]],
- * [@https://svn.boost.org/trac/boost/ticket/8420 #8420: ['"move's is_convertible does not compile with aligned data"]].
- [endsect]
- [section:release_notes_boost_1_55_00 Boost 1.55 Release]
- * Fixed bugs [@https://svn.boost.org/trac/boost/ticket/7952 #7952],
- [@https://svn.boost.org/trac/boost/ticket/8764 #8764],
- [@https://svn.boost.org/trac/boost/ticket/8765 #8765],
- [@https://svn.boost.org/trac/boost/ticket/8842 #8842],
- [@https://svn.boost.org/trac/boost/ticket/8979 #8979].
- [endsect]
- [section:release_notes_boost_1_54_00 Boost 1.54 Release]
- * Fixed bugs [@https://svn.boost.org/trac/boost/ticket/7969 #7969],
- [@https://svn.boost.org/trac/boost/ticket/8231 #8231],
- [@https://svn.boost.org/trac/boost/ticket/8765 #8765].
- [endsect]
- [section:release_notes_boost_1_53_00 Boost 1.53 Release]
- * Better header segregation (bug
- [@https://svn.boost.org/trac/boost/ticket/6524 #6524]).
- * Small documentation fixes
- * Replaced deprecated BOOST_NO_XXXX with newer BOOST_NO_CXX11_XXX macros.
- * Fixed [@https://svn.boost.org/trac/boost/ticket/7830 #7830],
- [@https://svn.boost.org/trac/boost/ticket/7832 #7832].
- [endsect]
- [section:release_notes_boost_1_51_00 Boost 1.51 Release]
- * Fixed bugs
- [@https://svn.boost.org/trac/boost/ticket/7095 #7095],
- [@https://svn.boost.org/trac/boost/ticket/7031 #7031].
- [endsect]
- [section:release_notes_boost_1_49_00 Boost 1.49 Release]
- * Fixed bugs
- [@https://svn.boost.org/trac/boost/ticket/6417 #6417],
- [@https://svn.boost.org/trac/boost/ticket/6183 #6183],
- [@https://svn.boost.org/trac/boost/ticket/6185 #6185],
- [@https://svn.boost.org/trac/boost/ticket/6395 #6395],
- [@https://svn.boost.org/trac/boost/ticket/6396 #6396],
- [endsect]
- [endsect]
- [xinclude autodoc.xml]
|