[英]Why does a static namespace variable accessed from inside an inline class method work?
我最近在一个头文件中看到了这段代码,并且惊讶于它的工作原理:
namespace NS {
static int uid = 0;
class X {
public:
static int getUID() { return uid++; }
};
}
如果从几个不同的C ++源文件中调用静态方法NS::X::getUID()
,我很惊讶地发现它正确生成了一个唯一的ID(在翻译单元中是唯一的)。 我认为命名空间范围中的静态变量与翻译单元有内部链接。 这里发生了什么? X类中的内联静态方法是否具有自己的转换单元,这就是它生成唯一ID的原因? 或者由于编译器的怪癖,它是否适合我?
上面的代码是否依赖于“安全”明确定义的行为? 如果是这样,这是一种在内联或模板类中生成唯一ID的令人惊讶的简洁方法,即使它看起来有点笨拙。 或者为这样的静态唯一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;
}
令人惊讶的输出(在从main调用这些之后)是:
File1, UID1: 0, UID2: 1
File2, UID1: 2, UID2: 3
如果您只将此标头包含在单个源文件中,则您的代码才是正确的。
因为uid
被声明为static
,所以它具有内部链接。 每个源文件都有一个uid
变量实例,其中包含此标头。 如果在三个源文件中包含此标头,则会有三个uid
变量。
getUid
函数是隐式inline
因为它是在类定义中定义的。 它是static
成员函数的事实是无关紧要的。 inline
函数的规则是必须在使用它的每个源文件中定义inline
函数,并且所有定义必须相同。
您getUid
函数定义违反此规则:是的,它在包括报头(因为它是在报头中定义的)每个源文件被限定,但各定义是不同的,因为在每一个定义的uid
称为是一个不同的uid
可变。
因此,您的程序违反了One Definition Rule并显示未定义的行为。 你观察到的特定行为可能是因为编译器采内联函数的一个定义,只是放弃休息,所以“全局变量”,你认为你正在使用恰好是一个 uid
变量-哪一个被引用由编译器保存的getUid
副本。 虽然这是这种形式的未定义行为的典型表现,但行为仍未定义。
您可以使uid
变量function-local以确保只有一个实例,并避免违反One Definition Rule:
namespace NS {
class X {
public:
static int getUID() {
static int uid = 0;
return uid++;
}
};
}
在这种情况下,保证程序中只有一个uid
实例。
我相信你的编译器会通过不内联 getUID()
方法来欺骗你。 getUID()
隐式内联的事实并不意味着实际内联 - 它只是对编译器的推荐。
除此之外,你getUID()
:UID有内部链接, getUID()
也可以返回非唯一ID。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.