3

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?

4

2 回答 2

6

静态变量只初始化一次。

跳过初始化的第二次(也是随后的)时间。

这里还有 2 个不同的功能test。每个唯一模板参数类型为 1。

一个示例,对于您的代码的简单函数调用:

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

这将产生以下汇编代码,您可以在其中看到有一个检查来验证变量是否已经初始化或返回已经设置的值。如果尚未设置,则将以线程安全的方式设置。

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
于 2020-01-18T12:06:22.827 回答
2

这里,static const int y = x; yisconst表示它是non-mutablestatic是程序中的存储时间。

如果您尝试在后续语句中直接修改,编译器会抛出错误,如果y尝试间接修改,则会出现未定义的行为。

从 c++ 参考,

const object - 类型为 const 限定的对象,或 const 对象的非可变子对象。这样的对象不能被修改:直接尝试这样做是编译时错误,并且尝试间接这样做(例如,通过引用或指向非 const 类型的指针修改 const 对象)会导致未定义的行为。

于 2020-01-18T12:26:01.630 回答