Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does mutable member disable const optimizations for non-mutable members?

As far as I know in C++ struct/class members with the same access control are stored in memory in declaration order. Is next example m and c should be stored one after the other:

#include <cstdlib>
#include <iostream>

struct X
{
    mutable int m;
    int         c;
};

const X cx = {0, 1};

int main()
{   
    X& x = const_cast<X&>(cx);

    x.m = rand();
    x.c = rand();

    std::cout<<x.m<<" "<<x.c;
}

In this example the program runs and prints 2 random numbers. If I remove mutable it crashes because cx is stored in readonly protected memory.

This made me wonder - does one mutable member disable const optimizations for the entire struct(somehow make all members mutable)?

Is it possible to store parts of a struct in readonly memory and other parts on non-readonly memory and respect C++ standard memory layout?

This was tested using Visual Studio 2010 on Windows 7 and GCC 4.7.2 on Ubuntu.

like image 818
Mircea Ispas Avatar asked Sep 03 '13 07:09

Mircea Ispas


People also ask

Why might you declare member data mutable?

mutable is particularly useful if most of the members should be constant but a few need to be updatable. Data members declared as mutable can be modified even though they are the part of object declared as const. You cannot use the mutable specifier with names declared as static or const, or reference.

What is a mutable member?

Mutable data members are those members whose values can be changed in runtime even if the object is of constant type. It is just opposite to constant. Sometimes logic required to use only one or two data member as a variable and another one as a constant to handle the data.

What is mutable mutex?

Mutex and mutable go together (M&M rule, C++11) A mutable member variable is presumed to be a shared variable so it should be synchronized with a mutex (or made atomic) If a member variable is itself a mutex, it should be mutable. This is required to use it inside a const member function.

What is volatile and mutable in C++?

mutable : The mutable keyword overrides any enclosing const statement. A mutable member of a const object can be modified. volatile : The volatile keyword is an implementation-dependent modifier, used when declaring variables, which prevents the compiler from optimizing those variables.


3 Answers

The standard talks about mutable members in many places. I quote below three parts of the standard explaining that you can modify only the mutable members of a const object. Otherwise it is Undefined Behaviour.

3.9.3 CV-qualifiers [basic.type.qualifier]

A const object is an object of type const T or a non-mutable subobject of such an object.

[...]

7.1.1 Storage class specifiers [dcl.stc]

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.

[...]

7.1.6.1 The cv-qualifiers [dcl.type.cv]

Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior.


Is it possible to store parts of a struct in readonly memory and other parts on non-readonly memory and respect C++ standard memory layout?

No, it is impossible to store a parts of a struct (or class) in a different memory area than the rest of the object.

like image 180
Pierre Fourgeaud Avatar answered Nov 14 '22 23:11

Pierre Fourgeaud


The keyword "const" is more a label for the programmer team like "private" and "public" not a compiler directive or compiler hint. A compiler can use it for optimization but don't need to. The compiler have only to control the abuse and prevent it. So the behavior you see is totally ok. And no, it is impossible that parts of one struct instance or class instance exist in different memory areas (do not count mapping in). Because that decision would impact the use of the struct and has to be allowed by the programmer.

like image 33
Martin Schlott Avatar answered Nov 14 '22 22:11

Martin Schlott


To explain why the compiler has to do "all or nothing" when it comes to where to store the struct: In most processors, memory pages are 4KB (a few has 8KB pages). That is the granularity of "read only" vs "read/write" memory blocks. So you can't have one 4-byte integer in read-only memory, and then the next 4 byte integer in read-write memory (unless they are exactly straddling a 4KB memory boundary - but that would definitely make for quite wasteful use of memory if you have an array of 3000 of them, taking up 12MB).

Note that this is not an "optimisation". Read-only memory is not faster than read-write memory. It's a protection against users being silly with const and writing to the data they shouldn't write to.

Also if you add a constructor that "does something" to your struct, it will most likely store the struct in read-write memory, because it's quite tricky for the compiler to generate code to switch read-only on and off at runtime.

like image 24
Mats Petersson Avatar answered Nov 14 '22 23:11

Mats Petersson