c – 为什么从内联类方法中访问的静态名称空间变量可以工作?
我最近在头文件中看到这个代码,令人惊讶的是它的工作:
namespace NS { static int uid = 0; class X { public: static int getUID() { return uid++; } }; } 如果从几个不同的C源文件调用静态方法NS :: X :: getUID(),我很惊讶地发现它正确地生成了唯一的ID(跨翻译单元).我认为命名空间范围中的一个静态变量与翻译单元有内部链接.这里发生了什么?类X中的内联静态方法是否具有自己的翻译单元,这就是为什么它生成唯一的ID?或者是因为我的编译器有点怪怪,这对我来说有用吗? 上述代码是否依赖于“安全”的明确行为?如果是这样,这是一个令人惊讶的简洁的方法来生成内联或模板类中的唯一ID,即使它看起来有点kludgy.或者更好地为这样的静态唯一ID函数生成一个新的C源文件,并在类中移动静态ID? 更新: 对于一个测试用例,我在不同的文件(file1.cpp,file2.cpp等)中写了几个这样的功能: #include "static_def.h" // Name of the above header file. void func1() { int uid1 = NS::X::getUID(); int uid2 = NS::X::getUID(); std::cout << "File1,UID1: " << uid1 << ",UID2: " << uid2 << std::endl; } 令人惊讶的输出(从主要调用这些输出后)是: File1,UID1: 0,UID2: 1 File2,UID1: 2,UID2: 3 解决方法
您的代码只有在您将此标题包含在单个源文件中时才正确.
因为uid被声明为静态,它具有内部链接.每个源文件都有一个uid变量的实例,其中包含此头.如果将这个头文件包含在三个源文件中,那么会有三个uid变量. getUid函数是隐式内联的,因为它定义在类定义的内部.它是静态成员函数的事实是无关紧要的.内联函数的规则是必须在其使用的每个源文件中定义内联函数,并且所有定义必须相同. 您的getUid函数定义违反了这个规则:是的,它在每个包含头文件的源文件中定义(因为它在头中定义),但每个定义是不同的,因为在每个定义中,引用的uid是一个不同的uid变量. 因此,您的程序违反“一维规则”,并表现出未定义的行为.您观察到的特定行为可能是因为编译器选择了内联函数的一个定义,并抛弃了其余的内容,所以您认为您正在使用的“全局变量”恰好恰好是uid变量之一 – 无论哪个被引用通过编译器保存的getUid的副本.虽然这是这种形式的未定义行为的典型表现,但行为仍未定义. 您可以使uid变量function-local来确保只有一个实例,并避免违反一个定义规则: namespace NS { class X { public: static int getUID() { static int uid = 0; return uid++; } }; } 在这种情况下,在程序中将只有一个uid实例被保证. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |