C & C++

C & C++

Made by DeepSource

Found throwing or partially-throwing move or move-assignment constructor CXX-P2008

Performance
Minor

A move or move-assignment constructor without noexcept or a noexcept with an expression that evaluates to boolean false.

The standard library expects all user types to always give the basic exception guarantee. This guarantee says that when an exception is thrown, the involved objects are still valid, even if in an unknown state, no resources are leaked. That is no fundamental language invariants are violated.

Hence, STL containers prefer using copy constructor over the move constructor when the latter doesn't provide a guarantee to not raise any exceptions. As if we only use copy, it has the guarantee: that it cannot modify the source.

This results in possibly unnecessary copies during the reorganization of the containers, potentially hurting the performance of the program.

Add noexcept or noexcept(true) to ensure that the move and move-assignment constructor are guaranteed to not raise exceptions.

Bad practice

#include <vector>

class A {
  public:
    A() {}
    A(const A&) {}
    A(A&&) {} // user-defined move constructor without noexcept
};

void foo(void)
{
  std::vector<A> v;
  for (int i=0; i < 5; ++i) {
    // on every iteration, the existing elements of type `A` are
    // copied before adding the new element at the end of the vector.
    v.push_back(A());
  }
}

Recommended

#include <vector>

class A {
  public:
    A() {}
    A(const A&) {}
    // noexcept ensures that the move happens without exception
    // and hence will be preferred by STL containers
    A(A&&) noexcept {}
};

void foo(void)
{
  std::vector<A> v;
  for (int i=0; i < 5; ++i) {
    // on every iteration, the existing elements of type `A`
    // will be moved before adding the new element at the end
    // of the vector.
    v.push_back(A());
  }
}