0

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

我想出了两种方法:

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

static int _initData = 0;

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

void helpMe()
{
    doSomethingWith(_initData);
}

或者我在原始辅助函数中使用静态函数变量和它的默认参数。

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

    doSomethingWith(_initData);
}

(假设 0 超出了 initData 的有效数据范围,并且我没有显示其他代码来确保在第一次调用该函数而不先启动它时引发错误。)

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

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

而且,为了使这更有趣,尽管它是 C++,但它不是用于面向对象的,而是用于过程代码。所以请不要回答提出对象或类的问题。想象一下它是具有 C++ 语法的 C。

4

3 回答 3

1

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

示例

如果你有两个翻译单元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);
}
于 2013-08-23T10:51:12.693 回答
1

我打算建议您将数据包装到一个对象中,直到我意识到您要求的是带有 C++ 标记的 C 解决方案...

您的两种解决方案都有其优点。

第二个是我更喜欢的一个,假设我们只是按照“它的样子/可维护性”。但是,如果helpMe使用 多次调用,则存在一个缺点,因为在第一种情况下不存在initData == 0extra 。如果函数足够长和/或编译器具有内联(并且是常量)的能力,if这可能会或可能不会成为问题。doSomethingWith()helpMeinitData

当然,代码中的某些东西也必须调用initHelpMe,所以无论如何它可能会是一样的。

总结:更喜欢第二种,基于隔离/封装。

于 2013-08-23T10:37:22.737 回答
0

我对这两种方式都有强烈的感觉。

首选选项 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);
}  
于 2013-08-23T14:40:56.090 回答