函数范围的静态变量如何导致与共享库中函数代码的未来使用不兼容

How a function-scoped static variable may lead to incompatibility with future uses of the function's code located in shared library

本文关键字:函数 代码 未来 不兼容 静态 范围 变量 何导致 共享      更新时间:2023-10-16

HIC++编码标准的规则3.3.1限制使用具有静态存储持续时间的变量,即使它们是在块范围内声明的:

具有

静态存储持续时间的块作用域对象的初始化顺序已明确定义。 但是,此类对象的生存期在程序终止时结束,这可能与代码的未来使用不兼容,例如作为共享库。

Application const & theApp()  
{  
  static  Application  app; // Non-Compliant  
  return  app;  
}

问题是不相容性会发生什么。

上。在我从@Employed-俄罗斯人那里得到合理的评论后,我意识到需要一些澄清。我可以想象多进程访问静态变量的一些问题。例如,在某些 Linux 实现中,相同的内存与分叉进程共享,直到第一次内存写入。它调用写入时复制。因此,如果我们在这样的系统上执行以下代码

#include <iostream>
#include <unistd.h>
using namespace std;
struct A
{
    A() {cout << __FUNCTION__ << 'n';}
    ~A() {cout << __FUNCTION__ << 'n';}
};
static void f()
{
    static A a;
}
int main()
{
    f();
    fork();    
    return 0;
}    

我们可以得到这样的输出

A
~A
~A

就是这样,析构函数的双重调用与构造函数的单一调用。这可能不应该是因为在其他系统上我们可以得到 A ~A A ~A .因此,我们可以想象静态变量的一些共同问题,但是共享库和块范围的静态的特殊问题是什么?

问题是不相容会发生什么。

例如,该库在多线程程序中可能变得不可用,其中并非所有线程在调用exit之前都终止。

也就是说,如果线程T0调用exit,则Application析构函数将在某个时候被调用(因为它在第一次调用theApp()时被atexit注册(。

如果线程 T1 仍在运行,并且具有对 theApp.app 的引用,则它现在将具有对已销毁对象的引用,并且可能会崩溃。

这被称为退出比赛,并且可能是高度不可复制的(如果T0T1有机会撞车之前到达sys_exit,您将观察到正常退出(。

更新:

析构函数的双重调用。这不应该是

错了:这完全按照应有的方式工作。这里没有对析构函数的双重调用:你有两个进程,每个进程都破坏自己的对象(它应该(。