3 ms·
The 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
by Kranar 11y ago
The 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.