Brian Silverman | 1f5d398 | 2018-08-04 23:37:52 -0700 | [diff] [blame^] | 1 | [/ |
| 2 | / Copyright (c) 2008-2010 Ion Gaztanaga |
| 3 | / |
| 4 | / Distributed under the Boost Software License, Version 1.0. (See accompanying |
| 5 | / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| 6 | /] |
| 7 | [library Boost.Move |
| 8 | [quickbook 1.5] |
| 9 | [authors [Gaztanaga, Ion]] |
| 10 | [copyright 2008-2014 Ion Gaztanaga] |
| 11 | [id move] |
| 12 | [dirname move] |
| 13 | [purpose Move semantics] |
| 14 | [license |
| 15 | Distributed under the Boost Software License, Version 1.0. |
| 16 | (See accompanying file LICENSE_1_0.txt or copy at |
| 17 | [@http://www.boost.org/LICENSE_1_0.txt]) |
| 18 | ] |
| 19 | ] |
| 20 | |
| 21 | [important To be able to use containers of movable-only values you will need to use containers |
| 22 | supporting move semantics, like [*Boost.Container] containers] |
| 23 | |
| 24 | [note Tested compilers: MSVC-7.1, 8.0, 9.0, GCC 4.3-MinGW in C++03 and C++0x modes, Intel 10.1] |
| 25 | |
| 26 | [section:what_is_boost_move What is Boost.Move?] |
| 27 | |
| 28 | Rvalue references are a major C++0x feature, enabling move semantics for C++ values. However, we |
| 29 | don't need C++0x compilers to take advantage of move semanatics. [*Boost.Move] emulates C++0x |
| 30 | move semantics in C++03 compilers and allows writing portable code that works optimally in C++03 |
| 31 | and C++0x compilers. |
| 32 | |
| 33 | [endsect] |
| 34 | |
| 35 | [section:introduction Introduction] |
| 36 | |
| 37 | [note |
| 38 | |
| 39 | The first 3 chapters are the adapted from the article |
| 40 | [@http://www.artima.com/cppsource/rvalue.html ['A Brief Introduction to Rvalue References]] |
| 41 | by Howard E. Hinnant, Bjarne Stroustrup, and Bronek Kozicki |
| 42 | |
| 43 | ] |
| 44 | |
| 45 | Copying can be expensive. For example, for vectors `v2=v1` typically involves a function call, |
| 46 | a memory allocation, and a loop. This is of course acceptable where we actually need two copies of |
| 47 | a vector, but in many cases, we don't: We often copy a `vector` from one place to another, just to |
| 48 | proceed to overwrite the old copy. Consider: |
| 49 | |
| 50 | [c++] |
| 51 | |
| 52 | template <class T> void swap(T& a, T& b) |
| 53 | { |
| 54 | T tmp(a); // now we have two copies of a |
| 55 | a = b; // now we have two copies of b |
| 56 | b = tmp; // now we have two copies of tmp (aka a) |
| 57 | } |
| 58 | |
| 59 | But, we didn't want to have any copies of a or b, we just wanted to swap them. Let's try again: |
| 60 | |
| 61 | [c++] |
| 62 | |
| 63 | template <class T> void swap(T& a, T& b) |
| 64 | { |
| 65 | T tmp(::boost::move(a)); |
| 66 | a = ::boost::move(b); |
| 67 | b = ::boost::move(tmp); |
| 68 | } |
| 69 | |
| 70 | This `move()` gives its target the value of its argument, but is not obliged to preserve the value |
| 71 | of its source. So, for a `vector`, `move()` could reasonably be expected to leave its argument as |
| 72 | a zero-capacity vector to avoid having to copy all the elements. In other words, [*move is a potentially |
| 73 | destructive copy]. |
| 74 | |
| 75 | In this particular case, we could have optimized swap by a specialization. However, we can't |
| 76 | specialize every function that copies a large object just before it deletes or overwrites it. That |
| 77 | would be unmanageable. |
| 78 | |
| 79 | In C++0x, move semantics are implemented with the introduction of rvalue references. They allow us to |
| 80 | implement `move()` without verbosity or runtime overhead. [*Boost.Move] is a library that offers tools |
| 81 | to implement those move semantics not only in compilers with `rvalue references` but also in compilers |
| 82 | conforming to C++03. |
| 83 | |
| 84 | [endsect] |
| 85 | |
| 86 | [section:implementing_movable_classes Implementing copyable and movable classes] |
| 87 | |
| 88 | [import ../example/doc_clone_ptr.cpp] |
| 89 | |
| 90 | [section:copyable_and_movable_cpp0x Copyable and movable classes in C++0x] |
| 91 | |
| 92 | Consider a simple handle class that owns a resource and also provides copy semantics |
| 93 | (copy constructor and assignment). For example a `clone_ptr` might own a pointer, and call |
| 94 | `clone()` on it for copying purposes: |
| 95 | |
| 96 | [c++] |
| 97 | |
| 98 | template <class T> |
| 99 | class clone_ptr |
| 100 | { |
| 101 | private: |
| 102 | T* ptr; |
| 103 | |
| 104 | public: |
| 105 | // construction |
| 106 | explicit clone_ptr(T* p = 0) : ptr(p) {} |
| 107 | |
| 108 | // destruction |
| 109 | ~clone_ptr() { delete ptr; } |
| 110 | |
| 111 | // copy semantics |
| 112 | clone_ptr(const clone_ptr& p) |
| 113 | : ptr(p.ptr ? p.ptr->clone() : 0) {} |
| 114 | |
| 115 | clone_ptr& operator=(const clone_ptr& p) |
| 116 | { |
| 117 | if (this != &p) |
| 118 | { |
| 119 | T *p = p.ptr ? p.ptr->clone() : 0; |
| 120 | delete ptr; |
| 121 | ptr = p; |
| 122 | } |
| 123 | return *this; |
| 124 | } |
| 125 | |
| 126 | // move semantics |
| 127 | clone_ptr(clone_ptr&& p) |
| 128 | : ptr(p.ptr) { p.ptr = 0; } |
| 129 | |
| 130 | clone_ptr& operator=(clone_ptr&& p) |
| 131 | { |
| 132 | if(this != &p) |
| 133 | { |
| 134 | std::swap(ptr, p.ptr); |
| 135 | delete p.ptr; |
| 136 | p.ptr = 0; |
| 137 | } |
| 138 | return *this; |
| 139 | } |
| 140 | |
| 141 | // Other operations... |
| 142 | }; |
| 143 | |
| 144 | `clone_ptr` has expected copy constructor and assignment semantics, duplicating resources when copying. |
| 145 | Note that copy constructing or assigning a `clone_ptr` is a relatively expensive operation: |
| 146 | |
| 147 | [copy_clone_ptr] |
| 148 | |
| 149 | `clone_ptr` is code that you might find in today's books on C++, except for the part marked as |
| 150 | `move semantics`. That part is implemented in terms of C++0x `rvalue references`. You can find |
| 151 | some good introduction and tutorials on rvalue references in these papers: |
| 152 | |
| 153 | * [@http://www.artima.com/cppsource/rvalue.html ['A Brief Introduction to Rvalue References]] |
| 154 | * [@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]] |
| 155 | |
| 156 | When the source of the copy is known to be a `rvalue` (e.g.: a temporary object), one can avoid the |
| 157 | potentially expensive `clone()` operation by pilfering source's pointer (no one will notice!). The move |
| 158 | constructor above does exactly that, leaving the rvalue in a default constructed state. The move assignment |
| 159 | operator simply does the same freeing old resources. |
| 160 | |
| 161 | Now when code tries to copy a rvalue `clone_ptr`, or if that code explicitly gives permission to |
| 162 | consider the source of the copy a rvalue (using `boost::move`), the operation will execute much faster. |
| 163 | |
| 164 | [move_clone_ptr] |
| 165 | |
| 166 | [endsect] |
| 167 | |
| 168 | [section:copyable_and_movable_cpp03 Copyable and movable classes in portable syntax for both C++03 and C++0x compilers] |
| 169 | |
| 170 | Many aspects of move semantics can be emulated for compilers not supporting `rvalue references` |
| 171 | and [*Boost.Move] offers tools for that purpose. With [*Boost.Move] we can write `clone_ptr` |
| 172 | so that it will work both in compilers with rvalue references and those who conform to C++03. |
| 173 | You just need to follow these simple steps: |
| 174 | |
| 175 | * Put the following macro in the [*private] section: |
| 176 | [macroref BOOST_COPYABLE_AND_MOVABLE BOOST_COPYABLE_AND_MOVABLE(classname)] |
| 177 | * Leave copy constructor as is. |
| 178 | * Write a copy assignment taking the parameter as |
| 179 | [macroref BOOST_COPY_ASSIGN_REF BOOST_COPY_ASSIGN_REF(classname)] |
| 180 | * Write a move constructor and a move assignment taking the parameter as |
| 181 | [macroref BOOST_RV_REF BOOST_RV_REF(classname)] |
| 182 | |
| 183 | Let's see how are applied to `clone_ptr`: |
| 184 | |
| 185 | [clone_ptr_def] |
| 186 | |
| 187 | [endsect] |
| 188 | |
| 189 | [*Question]: What about types that don't own resources? (E.g. `std::complex`?) |
| 190 | |
| 191 | No work needs to be done in that case. The copy constructor is already optimal. |
| 192 | |
| 193 | [endsect] |
| 194 | |
| 195 | [section:composition_inheritance Composition or inheritance] |
| 196 | |
| 197 | For classes made up of other classes (via either composition or inheritance), the move constructor |
| 198 | and move assignment can be easily coded using the `boost::move` function: |
| 199 | |
| 200 | [clone_ptr_base_derived] |
| 201 | |
| 202 | [important Due to limitations in the emulation code, a cast to `Base &` is needed before moving the base part in the move |
| 203 | constructor and call Base's move constructor instead of the copy constructor.] |
| 204 | |
| 205 | Each subobject will now be treated individually, calling move to bind to the subobject's move |
| 206 | constructors and move assignment operators. `Member` has move operations coded (just like |
| 207 | our earlier `clone_ptr` example) which will completely avoid the tremendously more expensive |
| 208 | copy operations: |
| 209 | |
| 210 | [clone_ptr_move_derived] |
| 211 | |
| 212 | Note above that the argument x is treated as a lvalue reference. That's why it is necessary to |
| 213 | say `move(x)` instead of just x when passing down to the base class. This is a key safety feature of move |
| 214 | semantics designed to prevent accidently moving twice from some named variable. All moves from |
| 215 | lvalues occur explicitly. |
| 216 | |
| 217 | [endsect] |
| 218 | |
| 219 | [section:movable_only_classes Movable but Non-Copyable Types] |
| 220 | |
| 221 | Some types are not amenable to copy semantics but can still be made movable. For example: |
| 222 | |
| 223 | * `unique_ptr` (non-shared, non-copyable ownership) |
| 224 | * A type representing a thread of execution |
| 225 | * A type representing a file descriptor |
| 226 | |
| 227 | By making such types movable (though still non-copyable) their utility is tremendously |
| 228 | increased. Movable but non-copyable types can be returned by value from factory functions: |
| 229 | |
| 230 | [c++] |
| 231 | |
| 232 | file_descriptor create_file(/* ... */); |
| 233 | //... |
| 234 | file_descriptor data_file; |
| 235 | //... |
| 236 | data_file = create_file(/* ... */); // No copies! |
| 237 | |
| 238 | In the above example, the underlying file handle is passed from object to object, as long |
| 239 | as the source `file_descriptor` is a rvalue. At all times, there is still only one underlying file |
| 240 | handle, and only one `file_descriptor` owns it at a time. |
| 241 | |
| 242 | To write a movable but not copyable type in portable syntax, you need to follow these simple steps: |
| 243 | |
| 244 | * Put the following macro in the [*private] section: |
| 245 | [macroref BOOST_MOVABLE_BUT_NOT_COPYABLE BOOST_MOVABLE_BUT_NOT_COPYABLE(classname)] |
| 246 | * Write a move constructor and a move assignment taking the parameter as |
| 247 | [macroref BOOST_RV_REF BOOST_RV_REF(classname)] |
| 248 | |
| 249 | Here's the definition of `file descriptor` using portable syntax: |
| 250 | |
| 251 | [import ../example/doc_file_descriptor.cpp] |
| 252 | [file_descriptor_def] |
| 253 | |
| 254 | [/ |
| 255 | /Many standard algorithms benefit from moving elements of the sequence as opposed to |
| 256 | /copying them. This not only provides better performance (like the improved `swap` |
| 257 | /implementation described above), but also allows these algorithms to operate on movable |
| 258 | /but non-copyable types. For example the following code sorts a `vector<unique_ptr<T>>` |
| 259 | /based on comparing the pointed-to types: |
| 260 | / |
| 261 | /[c++] |
| 262 | / |
| 263 | / struct indirect_less |
| 264 | / { |
| 265 | / template <class T> |
| 266 | / bool operator()(const T& x, const T& y) |
| 267 | / {return *x < *y;} |
| 268 | / }; |
| 269 | / ... |
| 270 | / std::vector<std::unique_ptr<A>> v; |
| 271 | / ... |
| 272 | / std::sort(v.begin(), v.end(), indirect_less()); |
| 273 | / |
| 274 | / |
| 275 | /As sort moves the unique_ptr's around, it will use swap (which no longer requires Copyability) |
| 276 | /or move construction / move assignment. Thus during the entire algorithm, the invariant that |
| 277 | /each item is owned and referenced by one and only one smart pointer is maintained. If the |
| 278 | /algorithm were to attempt a copy (say by programming mistake) a compile time error would result. |
| 279 | /] |
| 280 | |
| 281 | [endsect] |
| 282 | |
| 283 | [section:move_and_containers Containers and move semantics] |
| 284 | |
| 285 | Movable but non-copyable types can be safely inserted into containers and |
| 286 | movable and copyable types are more efficiently handled if those containers |
| 287 | internally use move semantics instead of copy semantics. |
| 288 | If the container needs to "change the location" of an element |
| 289 | internally (e.g. vector reallocation) it will move the element instead of copying it. |
| 290 | [*Boost.Container] containers are move-aware so you can write the following: |
| 291 | |
| 292 | [file_descriptor_example] |
| 293 | |
| 294 | [endsect] |
| 295 | |
| 296 | [section:construct_forwarding Constructor Forwarding] |
| 297 | |
| 298 | Consider writing a generic factory function that returns an object for a newly |
| 299 | constructed generic type. Factory functions such as this are valuable for encapsulating |
| 300 | and localizing the allocation of resources. Obviously, the factory function must accept |
| 301 | exactly the same sets of arguments as the constructors of the type of objects constructed: |
| 302 | |
| 303 | [c++] |
| 304 | |
| 305 | template<class T> T* factory_new() |
| 306 | { return new T(); } |
| 307 | |
| 308 | template<class T> T* factory_new(a1) |
| 309 | { return new T(a1); } |
| 310 | |
| 311 | template<class T> T* factory_new(a1, a2) |
| 312 | { return new T(a1, a2); } |
| 313 | |
| 314 | Unfortunately, in C++03 the much bigger issue with this approach is that the N-argument case |
| 315 | would require 2^N overloads, immediately discounting this as a general solution. Fortunately, |
| 316 | most constructors take arguments by value, by const-reference or by rvalue reference. If these |
| 317 | limitations are accepted, the forwarding emulation of a N-argument case requires just N overloads. |
| 318 | This library makes this emulation easy with the help of `BOOST_FWD_REF` and |
| 319 | `boost::forward`: |
| 320 | |
| 321 | [import ../example/doc_construct_forward.cpp] |
| 322 | [construct_forward_example] |
| 323 | |
| 324 | Constructor forwarding comes in handy to implement placement insertion in containers with |
| 325 | just N overloads if the implementor accepts the limitations of this type of forwarding for |
| 326 | C++03 compilers. In compilers with rvalue references perfect forwarding is achieved. |
| 327 | |
| 328 | [endsect] |
| 329 | |
| 330 | [section:move_return Implicit Move when returning a local object] |
| 331 | |
| 332 | The C++ standard specifies situations where an implicit move operation is safe and the |
| 333 | compiler can use it in cases were the (Named) Return Value Optimization) can't be used. |
| 334 | The typical use case is when a function returns a named (non-temporary) object by value |
| 335 | and the following code will perfectly compile in C++11: |
| 336 | |
| 337 | [c++] |
| 338 | |
| 339 | //Even if movable can't be copied |
| 340 | //the compiler will call the move-constructor |
| 341 | //to generate the return value |
| 342 | // |
| 343 | //The compiler can also optimize out the move |
| 344 | //and directly construct the object 'm' |
| 345 | movable factory() |
| 346 | { |
| 347 | movable tmp; |
| 348 | m = ... |
| 349 | //(1) moved instead of copied |
| 350 | return tmp; |
| 351 | }; |
| 352 | |
| 353 | //Initialize object |
| 354 | movable m(factory()); |
| 355 | |
| 356 | |
| 357 | In compilers without rvalue references and some non-conforming compilers (such as Visual C++ 2010/2012) |
| 358 | the line marked with `(1)` would trigger a compilation error because `movable` can't be copied. Using a explicit |
| 359 | `::boost::move(tmp)` would workaround this limitation but it would code suboptimal in C++11 compilers |
| 360 | (as the compile could not use (N)RVO to optimize-away the copy/move). |
| 361 | |
| 362 | [*Boost.Move] offers an additional macro called [macroref BOOST_MOVE_RET BOOST_MOVE_RET] that can be used to |
| 363 | alleviate this problem obtaining portable move-on-return semantics. Let's use the previously presented |
| 364 | movable-only `movable` class with classes `copyable` (copy-only type), `copy_movable` (can be copied and moved) and |
| 365 | `non_copy_movable` (non-copyable and non-movable): |
| 366 | |
| 367 | [import ../example/copymovable.hpp] |
| 368 | [copy_movable_definition] |
| 369 | |
| 370 | and build a generic factory function that returns a newly constructed value or a reference to an already |
| 371 | constructed object. |
| 372 | |
| 373 | [import ../example/doc_move_return.cpp] |
| 374 | [move_return_example] |
| 375 | |
| 376 | [*Caution]: When using this macro in a non-conforming or C++03 |
| 377 | compilers, a move will be performed even if the C++11 standard does not allow it |
| 378 | (e.g. returning a static variable). The user is responsible for using this macro |
| 379 | only used to return local objects that met C++11 criteria. E.g.: |
| 380 | |
| 381 | [c++] |
| 382 | |
| 383 | struct foo |
| 384 | { |
| 385 | copy_movable operator()() const |
| 386 | { |
| 387 | //ERROR! The Standard does not allow implicit move returns when the object to be returned |
| 388 | //does not met the criteria for elision of a copy operation (such as returning a static member data) |
| 389 | //In C++03 compilers this will MOVE resources from cm |
| 390 | //In C++11 compilers this will COPY resources from cm |
| 391 | //so DON'T use use BOOST_MOVE_RET without care. |
| 392 | return BOOST_MOVE_RET(copy_movable, cm); |
| 393 | } |
| 394 | |
| 395 | static copy_movable cm; |
| 396 | }; |
| 397 | |
| 398 | |
| 399 | [*Note]: When returning a temporary object `BOOST_MOVE_REF` is not needed as copy ellision rules will work on |
| 400 | both C++03 and C++11 compilers. |
| 401 | |
| 402 | [c++] |
| 403 | |
| 404 | //Note: no BOOST_MOVE_RET |
| 405 | movable get_movable() |
| 406 | { return movable(); } |
| 407 | |
| 408 | copy_movable get_copy_movable() |
| 409 | { return copy_movable(); } |
| 410 | |
| 411 | copyable get_copyable() |
| 412 | { return copyable(); } |
| 413 | |
| 414 | |
| 415 | [endsect] |
| 416 | |
| 417 | [section:move_iterator Move iterators] |
| 418 | |
| 419 | [c++] |
| 420 | |
| 421 | template<class Iterator> |
| 422 | class move_iterator; |
| 423 | |
| 424 | template<class It> |
| 425 | move_iterator<It> make_move_iterator(const It &it); |
| 426 | |
| 427 | [classref boost::move_iterator move_iterator] is an iterator adaptor with the |
| 428 | same behavior as the underlying iterator |
| 429 | except that its dereference operator implicitly converts the value returned by the |
| 430 | underlying iterator's dereference operator to a rvalue reference: `boost::move(*underlying_iterator)` |
| 431 | It is a read-once iterator, but can have up to random access traversal characteristics. |
| 432 | |
| 433 | `move_iterator` is very useful because some generic algorithms and container insertion functions |
| 434 | can be called with move iterators to replace copying with moving. For example: |
| 435 | |
| 436 | [import ../example/movable.hpp] |
| 437 | [movable_definition] |
| 438 | |
| 439 | `movable` objects can be moved from one container to another using move iterators and insertion |
| 440 | and assignment operations.w |
| 441 | |
| 442 | [import ../example/doc_move_iterator.cpp] |
| 443 | [move_iterator_example] |
| 444 | |
| 445 | [endsect] |
| 446 | |
| 447 | [section:move_inserters Move inserters] |
| 448 | |
| 449 | Similar to standard insert iterators, it's possible to deal with move insertion in the same way |
| 450 | as writing into an array. A special kind of iterator adaptors, called move insert iterators, are |
| 451 | provided with this library. With regular iterator classes, |
| 452 | |
| 453 | [c++] |
| 454 | |
| 455 | while (first != last) *result++ = *first++; |
| 456 | |
| 457 | causes a range [first,last) to be copied into a range starting with result. The same code with |
| 458 | result being a move insert iterator will move insert corresponding elements into the container. |
| 459 | This device allows all of the copying algorithms in the library to work in the move insert mode |
| 460 | instead of the regular overwrite mode. This library offers 3 move insert iterators and their |
| 461 | helper functions: |
| 462 | |
| 463 | [c++] |
| 464 | |
| 465 | // Note: C models Container |
| 466 | template <typename C> |
| 467 | class back_move_insert_iterator; |
| 468 | |
| 469 | template <typename C> |
| 470 | back_move_insert_iterator<C> back_move_inserter(C& x); |
| 471 | |
| 472 | template <typename C> |
| 473 | class front_move_insert_iterator; |
| 474 | |
| 475 | template <typename C> |
| 476 | front_move_insert_iterator<C> front_move_inserter(C& x); |
| 477 | |
| 478 | template <typename C> |
| 479 | class move_insert_iterator; |
| 480 | |
| 481 | template <typename C> |
| 482 | move_insert_iterator<C> move_inserter(C& x, typename C::iterator it); |
| 483 | |
| 484 | |
| 485 | A move insert iterator is constructed from a container and possibly one of its iterators pointing |
| 486 | to where insertion takes place if it is neither at the beginning nor at the end of the container. |
| 487 | Insert iterators satisfy the requirements of output iterators. `operator*` returns the move insert |
| 488 | iterator itself. The assignment `operator=(T& x)` is defined on insert iterators to allow writing |
| 489 | into them, it inserts x right before where the insert iterator is pointing. In other words, an |
| 490 | `insert iterator` is like a cursor pointing into the container where the insertion takes place. |
| 491 | `back_move_iterator` move inserts elements at the end of a container, `front_insert_iterator` |
| 492 | move inserts elements at the beginning of a container, and `move_insert_iterator` move inserts |
| 493 | elements where the iterator points to in a container. `back_move_inserter`, `front_move_inserter`, |
| 494 | and `move_inserter` are three functions making the insert iterators out of a container. Here's |
| 495 | an example of how to use them: |
| 496 | |
| 497 | [import ../example/doc_move_inserter.cpp] |
| 498 | [move_inserter_example] |
| 499 | |
| 500 | [endsect] |
| 501 | |
| 502 | [section:move_algorithms Move algorithms] |
| 503 | |
| 504 | The standard library offers several copy-based algorithms. Some of them, like `std::copy` or |
| 505 | `std::uninitialized_copy` are basic building blocks for containers and other data structures. |
| 506 | This library offers move-based functions for those purposes: |
| 507 | |
| 508 | [c++] |
| 509 | |
| 510 | template<typename I, typename O> O move(I, I, O); |
| 511 | template<typename I, typename O> O move_backward(I, I, O); |
| 512 | template<typename I, typename F> F uninitialized_move(I, I, F); |
| 513 | template<typename I, typename F> F uninitialized_copy_or_move(I, I, F); |
| 514 | |
| 515 | |
| 516 | The first 3 are move variations of their equivalent copy algorithms, but copy assignment and |
| 517 | copy construction are replaced with move assignment and construction. The last one has the |
| 518 | same behaviour as `std::uninitialized_copy` but since several standand library implementations |
| 519 | don't play very well with `move_iterator`s, this version is a portable version for those |
| 520 | willing to use move iterators. |
| 521 | |
| 522 | [import ../example/doc_move_algorithms.cpp] |
| 523 | [move_algorithms_example] |
| 524 | |
| 525 | [endsect] |
| 526 | |
| 527 | [section:emulation_limitations Emulation limitations] |
| 528 | |
| 529 | Like any emulation effort, the library has some limitations users should take in |
| 530 | care to achieve portable and efficient code when using the library with C++03 conformant compilers: |
| 531 | |
| 532 | [section:emulation_limitations_base Initializing base classes] |
| 533 | |
| 534 | When initializing base classes in move constructors, users must |
| 535 | cast the reference to a base class reference before moving it or just |
| 536 | use `BOOST_MOVE_BASE`. Example: |
| 537 | |
| 538 | [c++] |
| 539 | |
| 540 | Derived(BOOST_RV_REF(Derived) x) // Move ctor |
| 541 | : Base(boost::move(static_cast<Base&>(x))) |
| 542 | //... |
| 543 | |
| 544 | or |
| 545 | |
| 546 | [c++] |
| 547 | |
| 548 | Derived(BOOST_RV_REF(Derived) x) // Move ctor |
| 549 | : Base(BOOST_MOVE_BASE(Base, x)) |
| 550 | //... |
| 551 | |
| 552 | If casting is not performed the emulation will not move construct |
| 553 | the base class, because no conversion is available from `BOOST_RV_REF(Derived)` to |
| 554 | `BOOST_RV_REF(Base)`. Without the cast or `BOOST_MOVE_BASE` we might obtain a compilation |
| 555 | error (for non-copyable types) or a less-efficient move constructor (for copyable types): |
| 556 | |
| 557 | [c++] |
| 558 | |
| 559 | //If Derived is copyable, then Base is copy-constructed. |
| 560 | //If not, a compilation error is issued |
| 561 | Derived(BOOST_RV_REF(Derived) x) // Move ctor |
| 562 | : Base(boost::move(x)) |
| 563 | //... |
| 564 | |
| 565 | [endsect] |
| 566 | |
| 567 | [section:template_parameters Template parameters for perfect forwarding] |
| 568 | |
| 569 | The emulation can't deal with C++0x reference collapsing rules that allow perfect forwarding: |
| 570 | |
| 571 | [c++] |
| 572 | |
| 573 | //C++0x |
| 574 | template<class T> |
| 575 | void forward_function(T &&t) |
| 576 | { inner_function(std::forward<T>(t); } |
| 577 | |
| 578 | //Wrong C++03 emulation |
| 579 | template<class T> |
| 580 | void forward_function(BOOST_RV_REF<T> t) |
| 581 | { inner_function(boost::forward<T>(t); } |
| 582 | |
| 583 | In C++03 emulation BOOST_RV_REF doesn't catch any const rlvalues. For more details on |
| 584 | forwarding see [link move.construct_forwarding Constructor Forwarding] chapter. |
| 585 | |
| 586 | [endsect] |
| 587 | |
| 588 | [section:emulation_limitations_binding Binding of rvalue references to lvalues] |
| 589 | |
| 590 | The |
| 591 | [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html first rvalue reference] |
| 592 | proposal allowed the binding of rvalue references to lvalues: |
| 593 | |
| 594 | [c++] |
| 595 | |
| 596 | func(Type &&t); |
| 597 | //.... |
| 598 | |
| 599 | Type t; //Allowed |
| 600 | func(t) |
| 601 | |
| 602 | |
| 603 | Later, as explained in |
| 604 | [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2812.html ['Fixing a Safety Problem with Rvalue References]] |
| 605 | this behaviour was considered dangerous and eliminated this binding so that rvalue references adhere to the |
| 606 | principle of type-safe overloading: ['Every function must be type-safe in isolation, without regard to how it has been overloaded] |
| 607 | |
| 608 | [*Boost.Move] can't emulate this type-safe overloading principle for C++03 compilers: |
| 609 | |
| 610 | [c++] |
| 611 | |
| 612 | //Allowed by move emulation |
| 613 | movable m; |
| 614 | BOOST_RV_REF(movable) r = m; |
| 615 | |
| 616 | [endsect] |
| 617 | |
| 618 | [section:assignment_operator Assignment operator in classes derived from or holding copyable and movable types] |
| 619 | |
| 620 | The macro [macroref BOOST_COPYABLE_AND_MOVABLE BOOST_COPYABLE_AND_MOVABLE] needs to |
| 621 | define a copy constructor for `copyable_and_movable` taking a non-const parameter in C++03 compilers: |
| 622 | |
| 623 | [c++] |
| 624 | |
| 625 | //Generated by BOOST_COPYABLE_AND_MOVABLE |
| 626 | copyable_and_movable &operator=(copyable_and_movable&){/**/} |
| 627 | |
| 628 | Since the non-const overload of the copy constructor is generated, compiler-generated |
| 629 | assignment operators for classes containing `copyable_and_movable` |
| 630 | will get the non-const copy constructor overload, which will surely surprise users: |
| 631 | |
| 632 | [c++] |
| 633 | |
| 634 | class holder |
| 635 | { |
| 636 | copyable_and_movable c; |
| 637 | }; |
| 638 | |
| 639 | void func(const holder& h) |
| 640 | { |
| 641 | holder copy_h(h); //<--- ERROR: can't convert 'const holder&' to 'holder&' |
| 642 | //Compiler-generated copy constructor is non-const: |
| 643 | // holder& operator(holder &) |
| 644 | //!!! |
| 645 | } |
| 646 | |
| 647 | This limitation forces the user to define a const version of the copy assignment, |
| 648 | in all classes holding copyable and movable classes which might be annoying in some cases. |
| 649 | |
| 650 | An alternative is to implement a single `operator =()` for copyable and movable classes |
| 651 | [@http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ using "pass by value" semantics]: |
| 652 | |
| 653 | [c++] |
| 654 | |
| 655 | T& operator=(T x) // x is a copy of the source; hard work already done |
| 656 | { |
| 657 | swap(*this, x); // trade our resources for x's |
| 658 | return *this; // our (old) resources get destroyed with x |
| 659 | } |
| 660 | |
| 661 | However, "pass by value" is not optimal for classes (like containers, strings, etc.) that reuse resources |
| 662 | (like previously allocated memory) when x is assigned from a lvalue. |
| 663 | |
| 664 | [endsect] |
| 665 | |
| 666 | [section:templated_assignment_operator Templated assignment operator in copyable and movable types] |
| 667 | |
| 668 | |
| 669 | [import ../example/doc_template_assign.cpp] |
| 670 | |
| 671 | Given a movable and copyable class, if a templated assignment operator (*) is added: |
| 672 | |
| 673 | [template_assign_example_foo_bar] |
| 674 | |
| 675 | C++98 and C++11 compilers will behave different when assigning from a `[const] Foo` lvalue: |
| 676 | |
| 677 | [template_assign_example_main] |
| 678 | |
| 679 | This different behaviour is a side-effect of the move emulation that can't be easily avoided by |
| 680 | [*Boost.Move]. One workaround is to SFINAE-out the templated assignment operator with `disable_if`: |
| 681 | |
| 682 | [c++] |
| 683 | |
| 684 | template<class U> // Modified templated assignment |
| 685 | typename boost::disable_if<boost::is_same<U, Foo>, Foo&>::type |
| 686 | operator=(const U& rhs) |
| 687 | { i = -rhs.i; return *this; } //(2) |
| 688 | |
| 689 | |
| 690 | [endsect] |
| 691 | |
| 692 | [endsect] |
| 693 | |
| 694 | [section:how_the_library_works How the library works] |
| 695 | |
| 696 | [*Boost.Move] is based on macros that are expanded to true rvalue references in C++0x compilers |
| 697 | and emulated rvalue reference classes and conversion operators in C++03 compilers. |
| 698 | |
| 699 | In C++03 compilers [*Boost.Move] defines a class named `::boost::rv`: |
| 700 | |
| 701 | [c++] |
| 702 | |
| 703 | template <class T> |
| 704 | class rv : public T |
| 705 | { |
| 706 | rv(); |
| 707 | ~rv(); |
| 708 | rv(rv const&); |
| 709 | void operator=(rv const&); |
| 710 | }; |
| 711 | |
| 712 | which is convertible to the movable base class (usual C++ derived to base conversion). When users mark |
| 713 | their classes as [macroref BOOST_MOVABLE_BUT_NOT_COPYABLE BOOST_MOVABLE_BUT_NOT_COPYABLE] or |
| 714 | [macroref BOOST_COPYABLE_AND_MOVABLE BOOST_COPYABLE_AND_MOVABLE], these macros define conversion |
| 715 | operators to references to `::boost::rv`: |
| 716 | |
| 717 | [c++] |
| 718 | |
| 719 | #define BOOST_MOVABLE_BUT_NOT_COPYABLE(TYPE)\ |
| 720 | public:\ |
| 721 | operator ::boost::rv<TYPE>&() \ |
| 722 | { return *static_cast< ::boost::rv<TYPE>* >(this); }\ |
| 723 | operator const ::boost::rv<TYPE>&() const \ |
| 724 | { return static_cast<const ::boost::rv<TYPE>* >(this); }\ |
| 725 | private:\ |
| 726 | //More stuff... |
| 727 | |
| 728 | [macroref BOOST_MOVABLE_BUT_NOT_COPYABLE BOOST_MOVABLE_BUT_NOT_COPYABLE] also declares a |
| 729 | private copy constructor and assignment. [macroref BOOST_COPYABLE_AND_MOVABLE BOOST_COPYABLE_AND_MOVABLE] |
| 730 | defines a non-const copy constructor `TYPE &operator=(TYPE&)` that forwards to a const version: |
| 731 | |
| 732 | #define BOOST_COPYABLE_AND_MOVABLE(TYPE)\ |
| 733 | public:\ |
| 734 | TYPE& operator=(TYPE &t)\ |
| 735 | { this->operator=(static_cast<const ::boost::rv<TYPE> &>(const_cast<const TYPE &>(t))); return *this;}\ |
| 736 | //More stuff... |
| 737 | |
| 738 | In C++0x compilers `BOOST_COPYABLE_AND_MOVABLE` expands to nothing and `BOOST_MOVABLE_BUT_NOT_COPYABLE` |
| 739 | declares copy constructor and assigment operator private. |
| 740 | |
| 741 | When users define the [macroref BOOST_RV_REF BOOST_RV_REF] overload of a copy constructor/assignment, in |
| 742 | C++0x compilers it is expanded to a rvalue reference (`T&&`) overload and in C++03 compilers it is expanded |
| 743 | to a `::boost::rv<T> &` overload: |
| 744 | |
| 745 | [c++] |
| 746 | |
| 747 | #define BOOST_RV_REF(TYPE) ::boost::rv< TYPE >& \ |
| 748 | |
| 749 | When users define the [macroref BOOST_COPY_ASSIGN_REF BOOST_COPY_ASSIGN_REF] overload, |
| 750 | it is expanded to a usual copy assignment (`const T &`) overload in C++0x compilers and |
| 751 | to a `const ::boost::rv &` overload in C++03 compilers: |
| 752 | |
| 753 | [c++] |
| 754 | |
| 755 | #define BOOST_COPY_ASSIGN_REF(TYPE) const ::boost::rv< TYPE >& |
| 756 | |
| 757 | As seen, in [*Boost.Move] generates efficient and clean code for C++0x move |
| 758 | semantics, without modifying any resolution overload. For C++03 compilers |
| 759 | when overload resolution is performed these are the bindings: |
| 760 | |
| 761 | * a) non-const rvalues (e.g.: temporaries), bind to `::boost::rv< TYPE >&` |
| 762 | * b) const rvalue and lvalues, bind to `const ::boost::rv< TYPE >&` |
| 763 | * c) non-const lvalues (e.g. non-const references) bind to `TYPE&` |
| 764 | |
| 765 | The library does not define the equivalent of |
| 766 | [macroref BOOST_COPY_ASSIGN_REF BOOST_COPY_ASSIGN_REF] for copy construction (say, `BOOST_COPY_CTOR_REF`) |
| 767 | because nearly all modern compilers implement RVO and this is much more efficient than any move emulation. |
| 768 | [funcref boost::move move] just casts `TYPE &` into `::boost::rv<TYPE> &`. |
| 769 | |
| 770 | Here's an example that demostrates how different rlvalue objects bind to `::boost::rv` references in the |
| 771 | presence of three overloads and the conversion operators in C++03 compilers: |
| 772 | |
| 773 | [import ../example/doc_how_works.cpp] |
| 774 | [how_works_example] |
| 775 | |
| 776 | [endsect] |
| 777 | |
| 778 | |
| 779 | [section:thanks_to Thanks and credits] |
| 780 | |
| 781 | Thanks to all that developed ideas for move emulation: the first emulation was based on Howard Hinnant |
| 782 | emulation code for `unique_ptr`, David Abrahams suggested the use of `class rv`, |
| 783 | and Klaus Triendl discovered how to bind const rlvalues using `class rv`. |
| 784 | |
| 785 | Many thanks to all boosters that have tested, reviewed and improved the library. |
| 786 | |
| 787 | Special thanks to: |
| 788 | |
| 789 | * Orson Peters, author of [@https://github.com/orlp/pdqsort Pattern-defeating quicksort (pdqsort)]. |
| 790 | * Andrey Astrelin, author of [@https://github.com/Mrrl/GrailSort Grail Sort]. |
| 791 | |
| 792 | [endsect] |
| 793 | |
| 794 | [section:release_notes Release Notes] |
| 795 | |
| 796 | [section:release_notes_boost_1_67 Boost 1.67 Release] |
| 797 | |
| 798 | * Added pdqsort and heap_sort implementations, initially as a detail, they will be official in the future once better tested. |
| 799 | |
| 800 | [endsect] |
| 801 | |
| 802 | [section:release_notes_boost_1_66 Boost 1.66 Release] |
| 803 | |
| 804 | * Fixed bugs: |
| 805 | * [@https://github.com/boostorg/move/pull/14 Git Pull #14: ['"Workaround for bogus [-Wignored-attributes] warning on GCC 6.x/7.x"]]. |
| 806 | * [@https://github.com/boostorg/move/issues/15 Git Issue #15: ['"Incorrect merge in adaptive_merge when the number of unique items is limited"]]. |
| 807 | |
| 808 | [endsect] |
| 809 | |
| 810 | |
| 811 | [section:release_notes_boost_1_65 Boost 1.65 Release] |
| 812 | |
| 813 | * Fixed bug: |
| 814 | * [@https://github.com/boostorg/move/pull/11 Git Pull #11: ['"replace 'std::random_shuffle' by '::random_shuffle'"]]. |
| 815 | * [@https://github.com/boostorg/move/pull/12 Git Pull #12: ['"Adds support for MSVC ARM64 target'"]]. |
| 816 | |
| 817 | [endsect] |
| 818 | |
| 819 | [section:release_notes_boost_1_64 Boost 1.64 Release] |
| 820 | |
| 821 | * Fixed bug: |
| 822 | * [@https://svn.boost.org/trac/boost/ticket/12920 #12920 ['"movelib::unique_ptr: incorrect pointer type for nested array"]]. |
| 823 | |
| 824 | [endsect] |
| 825 | |
| 826 | [section:release_notes_boost_1_62 Boost 1.62 Release] |
| 827 | |
| 828 | * Documented new limitations reported in Trac tickets |
| 829 | [@https://svn.boost.org/trac/boost/ticket/12194 #12194 ['"Copy assignment on moveable and copyable classes uses wrong type"]] and |
| 830 | [@https://svn.boost.org/trac/boost/ticket/12307 #12307 ['"Copy assignment from const ref handled differently in C++11/C++98"]]. |
| 831 | |
| 832 | [endsect] |
| 833 | |
| 834 | [section:release_notes_boost_1_61 Boost 1.61 Release] |
| 835 | |
| 836 | * Experimental: asymptotically optimal bufferless merge and sort algorithms: [funcref boost::movelib::adaptive_merge adaptive_merge] |
| 837 | and [funcref boost::movelib::adaptive_sort adaptive_sort]. |
| 838 | |
| 839 | * Fixed bug: |
| 840 | * [@https://svn.boost.org/trac/boost/ticket/11758 Trac #11758: ['"BOOST_MOVABLE_BUT_NOT_COPYABLE doesn't reset private access with rvalue ref version"]], |
| 841 | |
| 842 | [endsect] |
| 843 | |
| 844 | [section:release_notes_boost_1_60 Boost 1.60 Release] |
| 845 | |
| 846 | * Fixed bug: |
| 847 | * [@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"]], |
| 848 | |
| 849 | [endsect] |
| 850 | |
| 851 | [section:release_notes_boost_1_59 Boost 1.59 Release] |
| 852 | |
| 853 | * Changed `unique_ptr`'s converting constructor taking the source by value in C++03 compilers to allow simple conversions |
| 854 | from convertible types returned by value. |
| 855 | * Fixed bug: |
| 856 | * [@https://svn.boost.org/trac/boost/ticket/11229 Trac #11229: ['"vector incorrectly copies move-only objects using memcpy"]], |
| 857 | * [@https://svn.boost.org/trac/boost/ticket/11510 Trac #11510: ['"unique_ptr: -Wshadow warning issued"]], |
| 858 | |
| 859 | [endsect] |
| 860 | |
| 861 | [section:release_notes_boost_1_58_00 Boost 1.58 Release] |
| 862 | |
| 863 | * Added [macroref BOOST_MOVE_BASE BOOST_MOVE_BASE] utility. |
| 864 | * Added [funcref boost::adl_move_swap adl_move_swap] utility. |
| 865 | * Reduced dependencies on other Boost libraries to make the library a bit more lightweight. |
| 866 | * Fixed bugs: |
| 867 | * [@https://svn.boost.org/trac/boost/ticket/11044 Trac #11044: ['"boost::rv inherits off union, when such passed as template argument"]]. |
| 868 | |
| 869 | [endsect] |
| 870 | |
| 871 | [section:release_notes_boost_1_57_00 Boost 1.57 Release] |
| 872 | |
| 873 | * Added `unique_ptr` smart pointer. Thanks to Howard Hinnant for his excellent unique_ptr emulation code and testsuite. |
| 874 | * Added `move_if_noexcept` utility. Thanks to Antony Polukhin for the implementation. |
| 875 | * Fixed bugs: |
| 876 | * [@https://svn.boost.org/trac/boost/ticket/9785 Trac #9785: ['"Compiler warning with intel icc in boost/move/core.hpp"]], |
| 877 | * [@https://svn.boost.org/trac/boost/ticket/10460 Trac #10460: ['"Compiler error due to looser throw specifier"]], |
| 878 | * [@https://github.com/boostorg/move/pull/3 Git Pull #3: ['"Don't delete copy constructor when rvalue references are disabled"]], |
| 879 | |
| 880 | [endsect] |
| 881 | |
| 882 | [section:release_notes_boost_1_56_00 Boost 1.56 Release] |
| 883 | |
| 884 | * Added [macroref BOOST_MOVE_RET BOOST_MOVE_RET]. |
| 885 | * Fixed bugs: |
| 886 | * [@https://svn.boost.org/trac/boost/ticket/9482 #9482: ['"MSVC macros not undefined in boost/move/detail/config_end.hpp"]], |
| 887 | * [@https://svn.boost.org/trac/boost/ticket/9045 #9045: ['"Wrong macro name on docs"]], |
| 888 | * [@https://svn.boost.org/trac/boost/ticket/8420 #8420: ['"move's is_convertible does not compile with aligned data"]]. |
| 889 | |
| 890 | [endsect] |
| 891 | |
| 892 | [section:release_notes_boost_1_55_00 Boost 1.55 Release] |
| 893 | |
| 894 | * Fixed bugs [@https://svn.boost.org/trac/boost/ticket/7952 #7952], |
| 895 | [@https://svn.boost.org/trac/boost/ticket/8764 #8764], |
| 896 | [@https://svn.boost.org/trac/boost/ticket/8765 #8765], |
| 897 | [@https://svn.boost.org/trac/boost/ticket/8842 #8842], |
| 898 | [@https://svn.boost.org/trac/boost/ticket/8979 #8979]. |
| 899 | |
| 900 | [endsect] |
| 901 | |
| 902 | |
| 903 | [section:release_notes_boost_1_54_00 Boost 1.54 Release] |
| 904 | |
| 905 | |
| 906 | * Fixed bugs [@https://svn.boost.org/trac/boost/ticket/7969 #7969], |
| 907 | [@https://svn.boost.org/trac/boost/ticket/8231 #8231], |
| 908 | [@https://svn.boost.org/trac/boost/ticket/8765 #8765]. |
| 909 | |
| 910 | [endsect] |
| 911 | |
| 912 | [section:release_notes_boost_1_53_00 Boost 1.53 Release] |
| 913 | |
| 914 | * Better header segregation (bug |
| 915 | [@https://svn.boost.org/trac/boost/ticket/6524 #6524]). |
| 916 | * Small documentation fixes |
| 917 | * Replaced deprecated BOOST_NO_XXXX with newer BOOST_NO_CXX11_XXX macros. |
| 918 | * Fixed [@https://svn.boost.org/trac/boost/ticket/7830 #7830], |
| 919 | [@https://svn.boost.org/trac/boost/ticket/7832 #7832]. |
| 920 | |
| 921 | [endsect] |
| 922 | |
| 923 | [section:release_notes_boost_1_51_00 Boost 1.51 Release] |
| 924 | |
| 925 | * Fixed bugs |
| 926 | [@https://svn.boost.org/trac/boost/ticket/7095 #7095], |
| 927 | [@https://svn.boost.org/trac/boost/ticket/7031 #7031]. |
| 928 | |
| 929 | [endsect] |
| 930 | |
| 931 | [section:release_notes_boost_1_49_00 Boost 1.49 Release] |
| 932 | |
| 933 | * Fixed bugs |
| 934 | [@https://svn.boost.org/trac/boost/ticket/6417 #6417], |
| 935 | [@https://svn.boost.org/trac/boost/ticket/6183 #6183], |
| 936 | [@https://svn.boost.org/trac/boost/ticket/6185 #6185], |
| 937 | [@https://svn.boost.org/trac/boost/ticket/6395 #6395], |
| 938 | [@https://svn.boost.org/trac/boost/ticket/6396 #6396], |
| 939 | |
| 940 | [endsect] |
| 941 | |
| 942 | [endsect] |
| 943 | |
| 944 | [xinclude autodoc.xml] |