【问题标题】:Init values by using (somewhat) global variables vs. static function variables?通过使用(有点)全局变量与静态函数变量来初始化值?
【发布时间】:2013-08-23 10:27:40
【问题描述】:

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

我想出了两种方法:

我在 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 的有效数据范围,并且我没有显示其他代码以确保在第一次调用该函数而不先启动它时引发错误。)

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

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

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

【问题讨论】:

    标签: c++ c static initialization global-variables


    【解决方案1】:

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

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

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

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

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

    【讨论】:

      【解决方案2】:

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

      示例

      如果你有两个翻译单元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);
      }
      

      【讨论】:

      • 第三种解决方案仅限于 C++11,对吗?我知道至少 lambda 函数是,但我不确定 std::call_once 本身。
      【解决方案3】:

      我对双方都有强烈的感觉。

      首选选项 2 进行隔离,但选项 1 适合移植到 C++ 类。我已经编码了两种方式。它归结为 SW 架构。

      让我再提一点。

      两个选项的缺点:您没有限制初始化一次。 “需要用一些数据初始化一次”。看来 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);
      }  
      

      【讨论】:

      • 执行重新初始化的选项实际上是代码的一个受欢迎的功能。每次都将 initData 作为参数提供也是一种选择,但由于在整个代码中都使用了该函数并且我需要将 initData 传递给周围,因此这是不切实际的。避免发生的事情神奇地是我使用简单全局变量的原因。
      • 所以代码需要“用一些数据初始化至少一次”。明白了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-07
      • 1970-01-01
      相关资源
      最近更新 更多