Home > Mobile >  Impact of a mutable member on a complete const object and UB
Impact of a mutable member on a complete const object and UB

Time:05-22

A complete const object cannot be replaced per basic.life. Placement new will result in UB. This is a complete const object:

struct A {int i{};};
const A cco;

However, this, because it isn't a complete const object and only the subobject is const, may be replaced as of c 20:

struct A {const int i{};};
A o;

But what about this?

struct A {int i{}; mutable int mi{};};
const A o;

It looks like it's a complete const object. And the standard says: The mutable specifier on a class data member nullifies a const specifier applied to the containing class object.

It would thus seem that if it nullifies the containing class object then A is no longer const and it would no longer be a complete const object. So I decided to investigate what happens when I try to alter the object using a consteval function as well as run-time evaluation:

#include <memory>
#include <iostream>

struct A {
    int i{ 1 };
    mutable int mi{ 2 };
};

const A a;

consteval int foo()
{
    const A a;
    std::construct_at(&a, A{ 8,9 });
    return a.i;
}

int main()
{
    std::construct_at(&a, A{ 8,9 });
    std::cout << a.i << '\n';

    constexpr int cexpr_test = foo();
    std::cout << cexpr_test << '\n';
}

Both compile time and run time results in MSVC produce 8's which indicates the contents were replaced. However, this doesn't mean UB doesn't exist. Expanding this to compiler explorer shows that the modification also succeeded in GCC. But not in CLANG's run-time evaluation. Curiously, CLANG's consteval did modify the object.

So the question: Is it UB because the object remains a complete const object in spite of the standard's wording or is it UB and just wasn't picked up by any of the compiler's consteval at compile time?

CodePudding user response:

dcl.stc#9 says:

[Note 4: The mutable specifier on a class data member nullifies a const specifier applied to the containing class object and permits modification of the mutable class member even though the rest of the object is const ([basic.type.qualifier], [dcl.type.cv]). — end note]

(emphasis mine)

This means that a modification of only the mutable class member is permitted and if we try to modify any other non-mutable data members of such a const object the result will still be undefined as "the rest of the object is const".

In your example this means that only the mi mutable data member is permitted to be modified for a const A object and if we try to modify i the result will be undefined.

CodePudding user response:

Anything in the standard that is in a "Note" (such as [dcl.stc]/4, which you cited) is non-normative text. That is, the words have no actual force as far as the standard is concerned. You have to track down the actual part of the standard that explains more directly what mutable does.

The phrase "complete const object" merely refers to an object that has the properties of being both "complete" and "const". It is a complete object, per [intro.object]/2. It is a "const" object per [basic.type.qualifier]/1.1. Therefore it is "complete const" (or "const complete" as [basic.life]/11 calls it) and must follow the rules of such an object.

If those rules don't include affordances for mutable (and they don't), then mutable members are irrelevant.

  • Related