Search code examples
c++c++17reinterpret-castpointer-aliasingstdlaunder

Where can I find what std::launder really does?


I am trying to understand what std::launder does, and I hoped that by looking up an example implementation it would be clear.

Where can I find an example implementation of std::launder?

When I looked in lbic++ I see a code like

  template<typename _Tp>
    [[nodiscard]] constexpr _Tp*
    launder(_Tp* __p) noexcept
    { return __builtin_launder(__p); }

Which makes me think that this another of those compiler-magic functions.

What is that this function __builtin_launder can potentially do, does it simply add a tag to suppress compiler warnings about aliasing?

Is it possible to understand std::launder in terms of __builtin_launder or it just more compiler-magic (hooks)?


Solution

  • The purpose of std::launder is not to "suppress warnings" but to remove assumptions that the C++ compiler may have.

    Aliasing warnings are trying to inform you that you are possibly doing things whose behaviour is not defined by the C++ standard.

    The compiler can and does make assumptions that your code is only doing things defined by the standard. For example, it can assume that a pointer to a const value once constructed will not be changed.

    Compilers may use that assumption to skip refetching the value from memory (and store it in a register), or even calculate its value at compile time and do dead-code elimination based on it. It can assume this, because any program where it is false is doing undefined behaviour, so any program behaviour is accepted under the C++ standard.

    std::launder was crafted to permit you do things like take a pointer to a truly const value that was legally modified (by creating a new object in its storage, say) and use that pointer after the modification in a defined way (so it refers to the new object) and other specific and similar situations (don't assume it just "removes aliasing problems"). __builtin_launder is going to be a "noop" function in one sense, but in another sense it is going to change what kind of assembly code can be generated around it. With it, certain assumptions about what value can be reached from its input cannot be made about its output. And some code that would be UB on the input pointer is not UB on the output pointer.

    It is an expert tool. I, personally, wouldn't use it without doing a lot of standard delving and double checking that I wasn't using it wrong. It was added because there were certain operations someone proved there was no way to reasonably do in a standard compliant way, and it permits a library writer to do it efficiently now.