SirBob
SirBob

Reputation: 43

Why is it possible to modify a static const variable that is declared inside a function?

I'm implementing an ECS framework for my game engine and investigating ways to identify component types at runtime. This means I can dynamically group components of a similar type contiguously in memory. For example, I can have two separate arrays for Position and Velocity components that my systems can loop over.

I currently use typeid(), but I came across an article that uses static const variables to generate unique IDs for each type. The general idea can be summarized in the code snippet below:

#include <iostream>

struct Position { float x, y; };
struct Velocity { float dx, dy; };

template <typename T>
int test(int x) {
    static const int y = x;
    return y;
}

int main(int argc, char **argv) {
    std::cout << test<Position>(1) << " ";
    std::cout << test<Position>(2) << " ";
    std::cout << test<Velocity>(3) << " ";
    return 0;
}

This outputs 1 1 3, but I would expect that since it's attempting to modify a constant (specifically at the second call), it would fail to compile. Why does this work?

Upvotes: 4

Views: 730

Answers (2)

Robert Andrzejuk
Robert Andrzejuk

Reputation: 5222

Static variables are only initialized once.

The second (and consequent) time the initialization is skipped.

Here also you have 2 different functions test. 1 for each unique template parameter type.

An example, for a simple function call of Your code:

auto f() { return test<Position>(1); }

This will result in the following assembler code, where You can see that there is a check to verify if the variable has been already initialized or return the already set value. If it has not been set, then it will be set in a thread-safe manner.

f():
        movzx   eax, BYTE PTR guard variable for int test<Position>(int)::y[rip]
        test    al, al   // <----- check if intialized
        je      .L13     // <----- if not initialized go to .L13
                         // otherwise return the value
        mov     eax, DWORD PTR int test<Position>(int)::y[rip]
        ret
.L13:
        sub     rsp, 8
        mov     edi, OFFSET FLAT:guard variable for int test<Position>(int)::y
        call    __cxa_guard_acquire
        test    eax, eax
        jne     .L14
        mov     eax, DWORD PTR int test<Position>(int)::y[rip]
        add     rsp, 8
        ret
.L14:
        mov     DWORD PTR int test<Position>(int)::y[rip], 1
        mov     edi, OFFSET FLAT:guard variable for int test<Position>(int)::y
        call    __cxa_guard_release
        mov     eax, DWORD PTR int test<Position>(int)::y[rip]
        add     rsp, 8
        ret

Upvotes: 7

TruthSeeker
TruthSeeker

Reputation: 1579

Here, static const int y = x; y is const means it is non-mutable and static is storage duration in program.

Compiler throws error if you try to modify y directly in subsequent statement and it is undefined behavior if tried to modify indirectly.

From c++ reference,

const object - an object whose type is const-qualified, or a non-mutable subobject of a const object. Such object cannot be modified: attempt to do so directly is a compile-time error, and attempt to do so indirectly (e.g., by modifying the const object through a reference or pointer to non-const type) results in undefined behavior.

Upvotes: 3

Related Questions