#Is my understanding of noexcept move operations with the STL correct?

52 messages · Page 1 of 1 (latest)

empty silo
#

if I grab the vector<T>, and T has rule of 5 implemented, and the move constructor and move assignment operator are declared as noexcept(some_constexpr_boolean_expression) where some_constexpr_boolean_expression evaluates to true, then operations which are copying values of type T like push_back, insert, will use the move stuff of T, when resizing, or shifting all elements to the right by 1 position, otherwise deep copies and deep assignments for T will be used, in order to uphold the strong exception safety guarantee.

Is there any other benefit to having noexcept move stuff? Cause it looks like this is useful only for dynamic containers whose iterators get invalidated after adding elements, meaning linked lists, maps, stack, queue, etc have no use for the noexcept-ness of move stuff for T ? only the vector does?

raw atlasBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question run !howto ask.

whole crag
#

outside of containers that need to uphold exception guarantees like std::vector, there's rarely a benefit

#

the definition of the move constructor is typically visible, and if so, the compiler can reason on its own whether it needs to emit exception handling code

dull bolt
#

the main benefit of noexcept in general is being able to switch to a more efficient algorithm based on knowing that an exception will never come out of a given thing

#

that's about it

#

vector is the typical example yes

#

if reallocation needs to happen, vector will go and move its contents to the new place if the move is noexcept

whole crag
#

it's hard for me to come up with an example outside of algorithms that explicitly check if something is nothrow-movable

#

the only case I can come up with is move construction in a noexcept function, that makes clang emit extra code for uncaught exceptions

#

https://godbolt.org/z/dz1jbPMqa oddly enough, not for GCC

#

@dull bolt am I missing compiler flags or does GCC just handle uncaught exceptions in noexcept somewhere else

dull bolt
#

it might just get filtered out by goldbolt or smth

#

noexcept shouldn't result in any code generated inside the function

#

implementing noexcept really just means there needs to be a call to std::terminate linked into the exception handling tables to be called during unwinding

#

that's usually .cold code that's stored somewhere else in the binary since it will never run unless you are actually violating the noexcept

#

it might be that gcc just generates raw codebytes into some separate section or smth and so it doesn't show up in the asm there

#

in fact, it might be that you don't actually need any code to be generated for this 🤔

#

since it's just a call to std::terminate, i guess the compiler could just put the address of std::terminate in the unwinding handler in the eh table

whole crag
#

oddly enough, I'm not seeing any mention of std::terminate, even when disabling all filters

dull bolt
#

yeah i'm not entierly sure how this works

#

would have to look into the details of the eh info used by libstdc++

#

it might be that it just puts a flag somewhere that will make the runtime call terminate

#

¯_(ツ)_/¯

#

it definitely generates eh info that is not there if you remove the noexcept

#

so my guess would be that the runtime will call terminate during unwinding due to the eh info it generates

#

yeah, i think the personality routine will call terminate during unwinding

#

yeah

#

seems to be an issue with LLVM

empty silo
empty silo
dull bolt
#

yes

empty silo
#

makes perfect sense

dull bolt
#

vector generally can't move elements when resizing if moving might throw because if moving an element throws then resizing must fail but the vector must be in the state it was in before the resizing was attempted.

#

but if the move might throw then you can't reliably undo the move to restore the original state.

#

so as long as move may throw, vector has to resort to copying in order to provide the strong exception guarantee

empty silo
dull bolt
#

yeah

#

it's used in places

empty silo
#

ofc it has it 🙂

#

template metaprogramming shenanigans with std::move

#

or fallback to copy

#

!solved

raw atlasBOT
#

Thank you and let us know if you have any more questions!

empty silo
# dull bolt it's used in places

hold up... what about std::flat_map? (C++23)
it also will have non-stable iterators? (due to the internal raw buffer which needs to be resized)

#

this container will be the wet dream of every game dev who wants cache friendly hashmap

#

right?

dull bolt
#

no because it's not a hash map

empty silo
#
flat_map is similar to std::map but it's implemented by as an ordered sequence container. The underlying sequence container is by default vector but it can also work user-provided vector-like SequenceContainers (like static_vector or small_vector).

k