• Why std::vector requires noexcept move constructor?

    From Marcel Mueller@3:633/280.2 to All on Sun Jun 15 18:25:31 2025
    I discovered shortly that a move constructor that is not declared as
    noexcept is ignored by std::vector. Instead the objects are moved by the
    copy constructor.

    Why?
    The copy constructor is even more likely not declared as noexcept.


    Marcel

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: MB-NET.NET for Open-News-Network e.V. (3:633/280.2@fidonet)
  • From Paavo Helde@3:633/280.2 to All on Tue Jun 17 03:00:17 2025
    On 15.06.2025 11:25, Marcel Mueller wrote:
    I discovered shortly that a move constructor that is not declared as noexcept is ignored by std::vector. Instead the objects are moved by the copy constructor.

    A move constructor is a way to squeeze out max performance from the
    code. Noexcept also helps in this regard and is usually trivial to add
    to move operations.


    Why?
    The copy constructor is even more likely not declared as noexcept.


    Depending on the operation, it might be needed to restore the original
    state of existing data if an exception appears middle-way. With move
    this might become cumbersome or even impossible if there appears another exception during restore. Declaring the move operations noexcept gets
    rid of such problems.

    With copy constructors the original state is not touched at all so
    recovering from an exception is much simpler.



    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Marcel Mueller@3:633/280.2 to All on Tue Jun 17 04:50:28 2025
    Am 16.06.25 um 19:00 schrieb Paavo Helde:
    On 15.06.2025 11:25, Marcel Mueller wrote:
    I discovered shortly that a move constructor that is not declared as
    noexcept is ignored by std::vector. Instead the objects are moved by
    the copy constructor.

    A move constructor is a way to squeeze out max performance from the
    code.

    .... or to return non-copyable objects etc.

    Noexcept also helps in this regard and is usually trivial to add
    to move operations.

    Indeed. But if only one member has a move constructor w/o noexcept any
    auto generated move constructor silently misses noexcept too. I shortly
    run into this pitfall, and this caused excessive copying of objects at
    insert operations (with reallocation).


    Why?
    The copy constructor is even more likely not declared as noexcept.

    Depending on the operation, it might be needed to restore the original
    state of existing data if an exception appears middle-way.

    Ah, I wasn't aware that the operation is logically atomic.
    This is of course impossible with exceptions in between.

    With copy constructors the original state is not touched at all so recovering from an exception is much simpler.

    Indeed.

    Maybe a move constructor w/o noexcept should be a warning, because it
    makes no much sense to throw within a move operation.


    Marcel


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: MB-NET.NET for Open-News-Network e.V. (3:633/280.2@fidonet)
  • From Paavo Helde@3:633/280.2 to All on Tue Jun 17 15:48:44 2025
    On 16.06.2025 21:50, Marcel Mueller wrote:

    Maybe a move constructor w/o noexcept should be a warning, because it
    makes no much sense to throw within a move operation.

    It is a warning C26439 in VS2022, albeit you need to call the special
    code analysis step instead of standard code compilation.

    Analyze: Run Code analysis

    Build started at 08:43...
    ------ Build started: Project: ConsoleTest2022, Configuration: Debug
    x64 ------
    main.cpp
    C:\Test\ConsoleTestVS2022\ConsoleTest2022\main.cpp(6,7): warning
    C4625: 'bar': copy constructor was implicitly defined as deleted 1>C:\Test\ConsoleTestVS2022\ConsoleTest2022\main.cpp(6,7): warning
    C4626: 'bar': assignment operator was implicitly defined as deleted C:\Test\ConsoleTestVS2022\ConsoleTest2022\main.cpp(9): warning C26439:
    This kind of function should not throw. Declare it 'noexcept' (f.6).
    Done building project "ConsoleTest2022.vcxproj".
    ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ========== ========== Build completed at 08:43 and took 01,440 seconds ==========

    #include <iostream>
    #include <string>
    #include <vector>


    class bar {
    public:
    bar() = default;
    bar(bar&& b): s_(std::move(b.s_)) {}
    private:
    std::string s_;
    };

    int main() {
    std::vector<bar> bars;
    bars.push_back(bar());
    }


    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)