4 ms·
Remember, the most important thing to take away from RVO is that copy and move constructors should not have side-effects that change the behaviour of your progr
by nly 11y ago
Remember, the most important thing to take away from RVO is that copy and move constructors should not have side-effects that change the behaviour of your program (except for throwing an exception if they fail, and move constructors should be designed never to throw)
- Kranar 11y agoThe whole point of move constructors are observable side-effects. Furthermore move constructors often have to throw an exception due to the fact that moving an object should leave the original object in a valid state. Often times leaving the original object in a valid state requires involves performing an operation that could potentially fail. In the case of std::map and std::list, a conforming implementation may have to allocate memory in order for the original object to be in a valid state.
- nly 11y ago> The whole point of move constructors are observable side-effects. Nonsense. > Furthermore move constructors often have to throw an exception due to the fact that moving an object should leave the original object in a valid state. Whether or not move constructors should leave objects in a 'valid state', whatever you mean by that, is hotly contested. Personally I'm of the opinion the only valid operations on a moved-from object should be to move-assign to it (otherwise literally every mutating algorithm is broken) and, obviously, to destroy it. > Often times leaving the original object in a valid state requires involves performing an operation that could potentially fail. Which is exactly why I'm of the above opinion. Making move non-throwing is more or less always trivial and cheap, whereas doing so while ensuring a moved-from object has a valid and useful state, where all class invariants have been maintained, can be expensive. You should definitely favour a noexcept move constructor that results in an unspecified state over a implementing a throwing move. Just don't do it. If your move constructor throws then doing anything useful with your class becomes very expensive (because classes like std::vector will start copying your objects to move them around). > In the case of std::map and std::list, a conforming implementation may have to allocate memory in order for the original object to be in a valid state. This is just wrong. Moving a std::list will not throw provided the associated memory allocator is noexcept move constructible (and std::allocator is). The same is true of std::map.
- plorkyeran 11y agostd::list's move constructor is deliberately not specified to be noexcept even when the allocator's is, and in Dinkumware's implementation it actually can throw, since it allocates a new end sentinel for the moved-from list.
- nly 11y agoConstructors may need to allocate a sentinel, I see no reason for the move constructor to do so. I'd also question the performance benefits of having a sentinel (basically avoiding additional null pointer checks) has on performance given todays relative cache penalties.