【问题标题】:Where is it better to put the initialization code, before the loop or inside it?将初始化代码放在循环之前还是循环内部更好?
【发布时间】:2012-09-11 10:07:49
【问题描述】:

对不起,如果这是一个愚蠢的问题:-)

背景

我的旧代码如下所示:

struct {
int field1;
int field2;
int field3;
int field4;
... many many fields
} myStruct;


while (something) {
initialzationFunction(&myStruct);

// ...change fields of myStruct and do stuff.
}

while 循环的每次迭代都需要将 myStruct 初始化为某个值,比如说零。 initialzationFunction 将 myStruct 的所有字段初始化为零。

问题

把initialzationFunction放在while循环里面好不好, 还是在循环之前调用一次更好,如果他们碰巧更改了这段代码,让程序员“手动”初始化他们需要的东西。

编辑:不幸的是 myStruct 是一个全局变量,因此不能将其设为自动变量,除非我想将它作为参数传递给大量使用它的旧函数。

我的想法

  • 只需调用 initialzationFunction() 即可防止出现错误,以防有人修改代码并忘记稍后初始化 myStruct。
  • 查看初始化了哪些特定字段可能会提供更多信息。
  • 如果稍后在 while 循环中只修改少数字段,则调用初始化所有字段的 initialzationFunction() 是多余的。

你会怎么做?

【问题讨论】:

  • “你会做什么”——除非有性能问题或堆栈大小问题,否则我会在循环内定义并初始化 myStruct 作为自动变量。
  • Steve - 所以你赞成调用 initialzationFunction() ?因为结构有很多字段,自动变量有什么帮助?您仍然需要调用 initialzationFunction(),除非您想手动初始化所​​有字段,这需要大量代码。
  • 它会将变量限制在它应该使用的范围内,并具有适当的生命周期(将“它需要重新初始化”替换为“我们使用一个新的、已初始化的对象”) .定义和初始化将是相同的,但不必担心如何最好地重用对象,循环的每次迭代都使用自己的独立对象。这就是我默认编写代码的方式,直到出现其他一些要求。显然,如果结构是 27MB,并且循环的每次迭代只使用一个字段(每次不同的字段),那么其他要求就会侵入;-)

标签: c legacy-code


【解决方案1】:

如果您将代码留给他人维护,并且代码不是经过验证的热点,请每次初始化,因为他人引入的错误会更少。

如果代码是经过验证的关键热点,则初始化一次,然后清理代码。

过早的优化是万恶之源

【讨论】:

    【解决方案2】:

    由于结构字段在 while 循环内发生更改,因此在每次迭代期间初始化它是有意义的,无论循环中处理的目的是什么。

    我会说即使循环中没有修改,也可以重新初始化几个字段。但跟踪哪些字段被修改并排除这些字段 在下一次迭代期间进行初始化时会很麻烦,您可以不用。

    另一种方法是使用带有初始化值的临时结构变量,并在每次迭代开始时简单地分配它。

    【讨论】:

      【解决方案3】:

      嗯,理想情况下,您希望执行最少的操作来解决您正在解决的问题。按照这个逻辑,最好将initializationFunction 排除在循环之外,只更新循环迭代所需的字段。

      从维护的角度来看,如果有人忘记从您的struct 对象中重置成员,则循环中的算法可能会中断(或行为异常),那么最好在每个循环中初始化所有内容。但是,这并不能消除未来出现错误的可能性,它只会降低它的可能性。最后,这完全取决于维护者的能力水平。

      从性能的角度来看,这是一个micro optimization,这并不重要(除非你在初始化函数中做了一些耗时的事情)。

      【讨论】:

        【解决方案4】:

        这是一个平衡和复杂的问题。如果结构中的大多数成员在 while 循环中从未被访问过,那么初始化显然是多余的......但是为什么它们会在一个结构中组合在一起呢?他们最初的目的是什么?在这种情况下,代码本身比必要的复杂得多,尽管 C 中的空闲数据当然比从未执行的代码更容易混淆。

        如果在 while 循环中使用了 OTOH 结构成员的主要部分,那么仅对每个成员添加一个零赋值不会有太大影响,因为对该成员的每个后续操作都会或多或少地减轻初始化对性能的影响1/n 方式。

        我认为对代码维护不利的是 init 函数本身需要知道结构,这意味着您将信息分散到更多的地方而不是必要的地方。 IIRC C允许结构被memset清空(将结构触摸为无符号字符的向量)并且成员将真正出现0 ==>如果这是公然错误那么我很抱歉,有人可能会粉碎所有的打印版本标准在我头上。

        【讨论】:

        • C 标准不保证所有类型的 memset 为 0 与分配零相同。例如,空指针的表示不必全为 0 位,我认为 0.0 的表示也不需要。我不记得int 的填充位的规则是什么,但是表示0 需要全值位和符号位0 。大多数(几乎所有)C 实现确实保证 0/空指针由 0 位表示。
        【解决方案5】:

        如果结构必须在每次循环运行时都被初始化,那么在里面做就可以了。您还可以使用在循环之前初始化的虚拟结构,并使用memcpy 将清除的结构复制到循环内的真实结构中。

        或者像 Steve Jessop 所链接的问题的公认答案一样,不要使用memcpy,而是使用普通赋值,让编译器担心复制。

        【讨论】:

        猜你喜欢
        • 2015-03-30
        • 2011-01-09
        • 1970-01-01
        • 1970-01-01
        • 2019-01-11
        • 1970-01-01
        • 1970-01-01
        • 2018-07-09
        • 1970-01-01
        相关资源
        最近更新 更多