• Why std::vector requires noexcept move constructor?

    From Marcel Mueller@21:1/5 to All on Sun Jun 15 10: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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to Marcel Mueller on Mon Jun 16 20: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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Marcel Mueller@21:1/5 to All on Mon Jun 16 20: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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to Marcel Mueller on Tue Jun 17 08: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());
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)