Skip to content

<functional> : consider avoid branching for null move_only_function #5324

@AlexGuteniev

Description

@AlexGuteniev

In move_only_function we return special instance for null function:

STL/stl/inc/functional

Lines 1600 to 1609 in 0d8f517

_NODISCARD static const _Impl_t* _Get_impl(const _Move_only_function_data& _Data) noexcept {
static constexpr _Impl_t _Null_move_only_function = {
_Function_not_callable<_Rx, _Types...>,
nullptr,
nullptr,
};
const auto _Ret = static_cast<const _Impl_t*>(_Data._Impl);
return _Ret ? _Ret : &_Null_move_only_function;
}

We store nullptr and resolve it to the special impl each time impl is used, rather than just store that impl because of the DLL unload problem: if a DLL resets move_only_function to null, and then unloaded, the move_only_function should still function properly.

In vNext, we can put the special impl to the separately compiled STL code that is not unloaded (the STL DLL), and set null function to something permanent. This may be perf improvement.

Typically emitted code has a check and a conditional assignment, not an actual branch. But it is still about three extra instructions, although some of the cheapest ones.

There are some other consideration of implementing this suggestion:

  • ⚠ This will make impossible to add constexpr to some move_only_function constructors. See also: mutex
  • The impl will be not template-depenedent on function type, and so will not have function-specific call operator
    • The current call operator just calls abort() the new one would need to be nullptr and crash with memory access violation, apparently not very big loss
    • This will be beneficial to some extent, as it will further reduce code bloat (all move_only_functions wil share the instance)
    • It is actually possible to ignore calling conventions and implement it as no-reutrning function that takes no args and returns nothing, like _purecall_handler, but I think we won't be doing that here
  • The null check should be changed to look inside impl, it will be cheaper than comparing impl against specific value
  • There would be slight constructor pessimization.
    • The impl should be exposed as a variable, not as a getter function, if possible, to reduce that

Metadata

Metadata

Assignees

No one assigned

    Labels

    performanceMust go fastervNextBreaks binary compatibility

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions