Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can "an implicitly-defined move constructor" be NOT trivial?

cppreference defines "Trivial move constructor":

The move constructor for class T is trivial if all of the following is true:

  • it is NOT user-provided (meaning, it is implicitly-defined or defaulted);

  • T has no virtual member functions;T has no virtual base classes;

  • the move constructor selected for every direct base of T is trivial;

  • the move constructor selected for every non-static class type (or array of class type) member of T is trivial.

cppreference also defines "Implicitly-defined move constructor":

If the implicitly-declared move constructor is NEITHER deleted NOR trivial, it is defined (that is, a function body is generated and compiled) by the compiler if odr-used or needed for constant evaluation.

The implicitly-declared move constructor must NOT be deleted is obvious. But "it must NOT be trivial" sounds confusing to me.
Doesn't it mean that if it is NOT trivial then it should be "user-provided"? And if it already is "user-provided one" then why must "implicitly-declared one" kicks in?
So what wrong here? What is the point of an implicitly-declared move constructor must NOT be trivial? Please help.

like image 563
Rango Avatar asked Sep 06 '25 08:09

Rango


1 Answers

Doesn't it mean that if it is NOT trivial then it should be "user-provided"?

No. If the constructor is user-provided, it cannot be trivial. But not being trivial doesn't mean it cannot be implicitly-declared.

And if it already is "user-provided one" then why must "implicitly-declared one" kicks in?

I'm not sure what do you mean by this. A move constructor is either user-provided or implicitly-declared. If it is implicitly-declared, it can be trivial (if it meets more criteria).

Compare these two classes:

struct A {
    int a;
};

struct B {
    std::string b;
};

A has implicitly-defined and trivial move constructor. B has implicitly-declared, but non-trivial move constructor (because std::string has user-provided move constructor).

Both are implicitly-declared, meaning I didn't provide them, but they differ in implementation. Trivial move constructor needs not to be defined - that's the meaning of the second quote you provided. Compiler can simply replace it with std::memmove call. However, the non-trivial implicitly-declared move constructor must be defined (by the compiler) to call move constructors of each of the class members.


From yet another side, it could be presented like this:

  • Move constructor
    • user-provided
      • deleted
      • non-deleted (user-defined)
    • implicitly-declared
      • deleted
      • trivial (std::memmove)
      • non-trivial (implicitly defined, when used in the code, will not be defined if not used)
like image 106
Yksisarvinen Avatar answered Sep 08 '25 16:09

Yksisarvinen