C++ 通过使用(某种程度上)全局变量与静态函数变量初始化值?

C++ 通过使用(某种程度上)全局变量与静态函数变量初始化值?,c++,c,static,initialization,global-variables,C++,C,Static,Initialization,Global Variables,在整个代码中,我需要一些小的助手函数。 要工作,它们需要用一些数据初始化一次。 我应该在哪里存储init数据 我想出了两种方法: 我在helper.cpp文件的范围内创建静态变量,我使用专用的setter函数设置该文件,然后在helper函数中使用它 static int _initData = 0; void initHelpMe(int initData) { _initData = initData; } void helpMe() { doSomethingWith(

在整个代码中,我需要一些小的助手函数。 要工作,它们需要用一些数据初始化一次。 我应该在哪里存储init数据

我想出了两种方法:

我在helper.cpp文件的范围内创建静态变量,我使用专用的setter函数设置该文件,然后在helper函数中使用它

static int _initData = 0;

void initHelpMe(int initData)
{
    _initData = initData;
}

void helpMe()
{
    doSomethingWith(_initData);
}
或者我在原始的helper函数中使用一个静态函数变量和一个默认参数

void helpMe(int initData = 0)
{
    static int _initData = 0;
    if (initData != 0)
        _initData = initData;

    doSomethingWith(_initData);
}
(让我确认0超出了initData的有效数据范围,并且我没有显示额外的代码,以确保在首次调用函数而不首先启动它时引发错误。)

这两种方法的优点/缺点是什么?还有更好的方法吗

我当然喜欢第二种方法,因为它将所有功能保留在一个地方。但我已经知道它不是线程安全的(这在上午不是问题)


<>和,使这更有趣,虽然是C++,但这不是在面向对象中使用,而是在过程代码中使用。因此,请不要回答提出对象或类的问题。想象一下,它是C++的语法。

< p>我建议你把你的数据打包成一个对象,直到我意识到你在用C++标签请求C解决方案……p> 两种解决方案都有各自的优点

第二个是我更喜欢的,假设我们只看“它看起来像什么/可维护性”。但是,如果使用
initData==0
多次调用
helpMe
,则有一个缺点,因为在第一种情况下不存在额外的
if
。如果
doSomethingWith()
函数足够长,并且/或者编译器能够内联
helpMe
(并且
initData
是常量),则这可能是问题,也可能不是问题

当然,代码中的某些内容也必须调用
initHelpMe
,因此结果可能是一样的


总而言之:基于隔离/封装,我更喜欢第二个。

我显然更喜欢第二个!不同编译单元中的全局静态数据是按未指定的顺序初始化的(尽管是按一个单元的顺序)。函数的本地静态数据在第一次调用时初始化

示例

如果您有两个翻译单元A和B。单元A在初始化期间调用单元B的函数helpMe。假设初始化顺序为A,B。 第一个解决方案将零初始化_initData设置为某些initData。之后,单元B的初始化将_initData重置回零,并可能产生内存泄漏或其他危害

还有第三种解决方案:

void helpMe(int initData = 0)
{
    static std::once_flag once;
    static int _initData = 0;
    std::call_once(once, [&] {
        _initData = initData;
    }
    doSomethingWith(_initData);
}

我对这两方面都有强烈的感觉

首选隔离2,但选项1将其移植到C++类。我用两种方法编码。它可以归结为软件架构

让我再提一点

两个选项都有缺点:您没有将初始化限制为一次。“需要用一些数据初始化一次”。OP的条件似乎确保正确初始化
initHelpMe(123)
HelpMe(123)
,然后是
HelpMe()
,但不阻止/检测二次初始化

如果需要防止/检测二次故障,可以使用一些附加代码

// Initialization 
if (_initData != 0) {
  ; // Handle error
}
_initData = initData;

我使用的另一个范例如下。它可能无法在您的代码中实现,因为它不作为参数传递
initData
,但可以神奇地获得它

void helpMe(void) {
  static int Initialized = 0;
  if (!Initialized) {
    Initialized = 1;
    _initData = initData();
  }
  doSomethingWith(_initData);
}  

第三种解决方案仅限于C++11,对吗?我知道至少lambda函数是这样的,但我不确定std::call_once本身。执行重新初始化的选项实际上是代码的一个受欢迎的特性。每次都将initData作为参数也是一个选项,但不实用,因为函数在整个代码中都使用,我需要传递initData。我之所以不使用简单的全局变量,是因为避免了一些神奇的事情发生,所以代码需要“至少用一些数据初始化一次”。知道了。