Code optimizing and object memory layout don't obey the same rules
The C++ standard states the following about the memory layout of the objects:
1.8/2: Objects can contain other objects, called subobjects. A subobject can be a member subobject, a base class subobject, or an
array element. (...)
9.2/13: Nonstatic data members of a (non-union) class with the same access control are allocated so that later members have higher
addresses within a class object. The order of allocation of non-static
data members with different access control is unspecified.
Implementation alignment requirements might cause two adjacent members
not to be allocated immediately after each other; so might
requirements for space for managing virtual functions and virtual base
classes.
This guarantees that non static const members (which are data members, even if they are const) are contained within the object. So the compiler is not allowed to shorten the size of an object.
However, the compiler is authorized to perform code optimization such as constant propagation and dead code elimination, reordering, etc. as long as the observable behavior is not altered:
1.9/5: A conforming implementation executing a well-formed program shall produce the same observable behavior as one of the possible
executions of the corresponding instance of the abstract machine with
the same program and the same input. (...)
So if your const member is not volatile
nor atomic<>
, the compiler can very well generate
A obj(); // size not touched. And const member will be initialized if needed
int absoluteVal = 2; // constant propagation + inlining (the object is not even accessed)
Additional information
Here an example where the object can't be optimized away :
A obj(-2); // object is constructed
int absoluteVal = std::abs(obj.constVar); // will be optimized a way into = 2
std::cout<<absoluteVal<<std::endl;
size_t lo = sizeof(obj);
std::cout<<lo<<std::endl;
std::cout.write((char*)&obj, lo); // obj is written to a stream
// and output of content at &obj adress is observable behavior
You can see online on the optimizer results : despite the computation of absoluteVal
being optimized away, the object is instantiated in its full length and its constant is initialized:
...
mov esi, 2 ; this is absoluteVal calculation
mov DWORD PTR [rsp+12], -2 ; the const in [rsp+12] object is nevertheless initialized
...
lea rsi, [rsp+12] ; the address of the object
mov edx, 4 ; and its length
... ; are used to call cout.write()
call std::basic_ostream<char, std::char_traits<char> >::write(char const*, long)
This is because the observable behavior of writing this trivially copyable object to a stream requires every byte of the object to fit to the expectations.
sizeof(A)
. – Babbconst
class members. You can inline without eliminating the original function or object. – Lavonnacompile-time constant
withconstant
! – Organza