关于C++中全局内联函数的一个例子

Kla*_*men 3 c++ static pointers global inline

考虑到以下设置,我遇到了一个非常奇怪的现象,我无法解释.使用Visual Studio 2005,以下代码导致崩溃.我想知道原因.

playground.cpp

static int local=-1;    
#include "common.h"

int main(int arg)
{

  setit();     
  docastorUpdate();

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

COMMON.H

#include <stdio.h>
#include <iostream>

void docastorUpdate();

static int *gemini;

inline void setit()
{
  gemini = &local;
}
Run Code Online (Sandbox Code Playgroud)

castor.cpp

static int local = 2;

#include "common.h"

void docastorUpdate() {
  setit();

  // crashing here, dereferencing a null pointer
  std::cout << "castor:" << *gemini << std::endl; 
}
Run Code Online (Sandbox Code Playgroud)

问题是,当崩溃消失时

  1. 我将内联函数setit()移动到一个未命名的命名空间
  2. 我让它变得静止

简而言之,我需要帮助才能理解原因.任何建议表示赞赏!(我知道,这个解决方案不是最好的部分之一,只是好奇.)

R. *_*des 9

这会因为违反单定义规则而中断.单定义规则表明,在程序中,跨所有翻译单元,任何给定函数只有一个定义.inline这个规则是一个例外,它或多或少意味着"亲爱的编译器,这个函数会有几个定义,但它们都是一样的,我保证 ".

static,当在这里使用时local,意味着"亲爱的编译器,这是只有这个翻译单元才能看到的内部细节;请不要将它与local从其他翻译单元命名的变量混淆"

所以你向编译器承诺所有定义都是setit相同的,并要求编译器给每个翻译单元提供它自己的local变量.

但是,由于setit函数使用名称local范围内的任何变量,因此最终结果是两个不同的定义setit,每个定义使用不同的变量.你刚违背诺言.编译器信任你,结果是一个完全混乱的程序.它认为它可以根据你的承诺对代码做某些事情,但是既然你把它们背在背后,它试图用代码做的事情根本不起作用.


Lig*_*ica 5

您的代码以非常微妙的方式调用未定义的行为.

[C++11: 7.1.2/4]:内联函数应在每个使用ODR的翻译单元中定义,并且在每种情况下都应具有完全相同的定义.[..]

虽然定义看起来相同,因为它是由你的词法复制粘贴到每个翻译单元#include,但并不是因为&local在每种情况下都没有采用相同变量的地址.

因此,当您运行程序时,任何事情都可能发生,包括将您辛苦赚来的所有积蓄转移到我的银行帐户中,或者取走所有Jon Skeet的代表.

这就是使函数非inline解决问题的原因; 另外,将它放在一个未命名的命名空间中会使它在每个翻译单元中具有不同的功能.