mutable and “trivially fooable”

Pop quiz, hotshot.

struct M {
    M() = default;
    M(M&);
    M(const M&) = default;
};

Is M trivially move-constructible?

(Important background info: The C++ Standard considers both M(const M&) and M(M&) to be “copy constructors.”)

Clang and ICC (that’s the Intel C++ Compiler, which uses the EDG front-end) both say yes M is trivially move-constructible, because when you move-construct an M, you call the M(const M&) constructor, which is defaulted and thus (in this case) trivial.

GCC says no it isn’t. (UPDATE: I’ve filed this bug.)

MSVC correctly surmises that in this game, the only winning move is to sit in the corner and eat paste:

error C2580: M::M(const M &): multiple versions of a defaulted special member functions are not allowed


This quiz turns out to be tangentially important to P1144 “Object relocation in terms of move plus destroy,” because it exposes a case where the intuitive “rules of inheritance” with regard to trivial fooability do not apply.

struct N1 {
    mutable M m;
};

Assuming that we believe Clang and ICC (which I do) that M is trivially move-constructible, then so is N1. However,

struct N2 {
    mutable M m;
    N2(const N2&) = default;
};

N2 definitely is not trivially move-constructible, because if you try to move-construct an N2, it will call N2(const N2&), which will call M(M&) on the mutable member, which is user-provided.


So I’ve been vacillating on what the rules should be that decide if a class type is “naturally” trivially relocatable (that is, if the class type isn’t marked with the [[trivially_relocatable]] attribute).

Draft revision 7 as previously posted on this blog said:

A move-constructible, destructible object type T is a trivially relocatable type if it is:

  • a (possibly cv-qualified) class type declared with the [[trivially_relocatable]] attribute, or

  • a (possibly cv-qualified) class type which:

    • has either a defaulted, non-deleted move constructor or no move constructor and a defaulted, non-deleted copy constructor,

    • has no mutable members,

    • etc. etc.

In draft revision 12 I changed that to:

A move-constructible, destructible object type T is a trivially relocatable type if it is:

  • a (possibly cv-qualified) class type declared with the [[trivially_relocatable]] attribute, or

  • a (possibly cv-qualified) class type which:

    • either has a defaulted, non-deleted move constructor, or has no move constructor, a defaulted, non-deleted copy constructor, and no mutable or volatile subobjects,

    • etc. etc.

In draft revision 13 I’m considering changing it again to:

A move-constructible, destructible object type T is a trivially relocatable type if it is:

  • a (possibly cv-qualified) class type declared with the [[trivially_relocatable]] attribute, or

  • a (possibly cv-qualified) class type which:

    • has no deleted or user-provided move constructors,

    • has no deleted or user-provided copy constructors,

    • etc. etc.

Thoughts welcome!

Posted 2018-08-19