“静态计数器"对于类型的行为很奇怪 [英] "Static counter" for types behaves weirdly

查看:39
本文介绍了“静态计数器"对于类型的行为很奇怪的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个基于实体的组件系统,我正在尝试为组件类型分配一个特定的索引:

static std::size_t getNextTypeId() {静态 std::size_t lastTypeIdBitIdx{0};++lastTypeIdBitIdx;//这一行在问题结束时产生输出std::cout <<lastTypeIdBitIdx <<std::endl;返回 lastTypeIdBitIdx;}//我假设 TypeIdStorage::bitIdx 总是不同的//从 TypeIdStorage::bitIdx模板struct TypeIdStorage {静态常量 std::size_t bitIdx;};//这一行静态初始化bitIdx,获取下一个id模板const std::size_t TypeIdStorage::bitIdx{getNextTypeId()};

在我的游戏代码中,我声明了大约 20 种组件类型:

struct CPhysics : public sses::Component { ... };struct CHealth : public sses::Component { ... };struct CWeapon : public sses::Component { ... };//等等...

在我的实体系统代码中,我多次使用 TypeIdStorage<T>::bitIdxT 作为组件类型之一 - 我希望这会发生:

  • 如果 TypeIdStorage 存在,只需返回 TypeIdStorage::bitIdx.
  • 如果它不存在,则创建它并使用 getNextTypeId() 初始化 bitIdx.

这是我运行应用程序时打印的内容:

<块引用>

12312345678910111213141516...

调用 getNextTypeId() 怎么可能返回相同的数字?这种输出应该是不可能的.

难道不是保证静态变量会增加而不重复吗?我真的很困惑.

<小时>

使用 g++ 4.8.1clang++ 3.4调试发布 模式下进行测试.相同的输出.

valgrind 不打印任何有趣的东西.

clang++ 的 AddressSanitizer 也没有打印任何有趣的东西.

将我的程序的入口点设置为 int main() { return 0;} 产生完全相同的输出.问题是在编译时 - 但怎么可能呢?这对我来说似乎不可能.

解决方案

声明函数时需要去掉static:

std::size_t getNextTypeId() {//...}

确保仅存在此函数的一个版本.为此,您可能还需要将定义移动到实现文件中,并且只将声明保留在标题中.

如果声明函数static,则表示该符号不导出,只能在同一个翻译单元中使用.它不再在翻译单元之间共享.这导致每个翻译单元都有自己的函数副本,当然,每个副本都有自己的计数器.

I'm developing an entity-based component system, and I'm trying to assign a certain index to component types:

static std::size_t getNextTypeId() {
    static std::size_t lastTypeIdBitIdx{0};
    ++lastTypeIdBitIdx;

    // This line produces the output at the end of the question
    std::cout << lastTypeIdBitIdx << std::endl; 

    return lastTypeIdBitIdx;
}

// I'm assuming that TypeIdStorage<T1>::bitIdx will always be different
// from TypeIdStorage<T2>::bitIdx
template<typename T> struct TypeIdStorage { 
    static const std::size_t bitIdx; 
};

// This line statically initializes bitIdx, getting the next id
template<typename T> const std::size_t TypeIdStorage<T>::bitIdx{getNextTypeId()};

In my game code I have about 20 component types declared like this:

struct CPhysics : public sses::Component { ... };
struct CHealth : public sses::Component { ... };
struct CWeapon : public sses::Component { ... };
// and so on...

In my entity system code I use TypeIdStorage<T>::bitIdx with T being one of the component types several times - I expect this to happen:

  • If TypeIdStorage<T> exists, simply return TypeIdStorage<T>::bitIdx.
  • If it doesn't exist, create it and initialize bitIdx with getNextTypeId().

This is what is printed when I run the application:

1 2 3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ...

How is it possible that calling getNextTypeId() returns the same number? This kind of output should be impossible.

Isn't it guaranteed that the static variable will get incremented without repeating? I'm truly confused here.


Tested both with g++ 4.8.1 and clang++ 3.4, both in debug and release modes. Same output.

valgrind does not print anything interesting.

clang++'s AddressSanitizer does not print anything interesting either.

Setting my program's entry point to int main() { return 0; } produces exactly the same output. The issue is at compile-time - but how is it possible? This seems like an impossible situation to me.

解决方案

You need to drop the static when declaring the function:

std::size_t getNextTypeId() {
    // ...
}

to make sure only one version of this function exists. For this, you probably also need to move the definition to an implementation file and only leave the declaration in the header.

If you declare the function static, it means that the symbol is not exported and can only be used in the same translation unit. It is no longer shared between the translation units. This leads to each translation unit having its own copy of the function and each copy has, of course, its own counter.

这篇关于“静态计数器"对于类型的行为很奇怪的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆