【问题标题】:Is aggregate initialization of struct safe during refactor?重构期间结构的聚合初始化是否安全?
【发布时间】:2017-03-08 08:16:44
【问题描述】:

如果我有一个结构

SomeStruct
{
  double y;
  double x;
};

我在某处初始化它

SomeStruct s{1,2}; //y=1 x=2

如果我将结构重新排序为

,我的代码似乎可以静默地中断
SomeStruct
{
  double x;
  double y;
  double z;
};

从现在开始SomeStruct s{1,2} 表示 x=1, y=2, z=0

编辑: 提出的一个论点是构造函数也有同样的问题,这是正确的,但您通常可以在那里看到参数名称和顺序 - 如果使用任何现代 IDE 则更清楚。

我从未见过有人提到过这一点,但似乎只有在确定永远不会更改数据布局的情况下才能安全地使用这样的聚合初始化。那将是罕见的情况,那么有没有“永远不要在非同构结构上使用聚合初始化”的潜规则?

【问题讨论】:

  • 构造函数确实有同样的问题。这更多的是类型问题而不是初始化问题。
  • 但是如果你在你的构造函数中添加一个新对象,如果新的对象丢失,代码将无法编译。在问题中,代码会编译,没有人会意识到可能有错误。
  • @Ventu:好的,没错,但是如果你重新排序相同类型的字段,或者重新排序构造函数参数,你仍然可以引入静默更改。
  • @Kerrek SB 也对。

标签: c++ struct refactoring type-safety aggregate-initialization


【解决方案1】:

重构期间结构的聚合初始化安全吗?

取决于您在这种情况下如何定义“安全”。以及做了什么样的重构。

看来我的代码可以无声无息地破坏......因为现在SomeStruct s{1,2}意味着x=1, y=2, z=0

这可能完全没问题。为什么不应该将 z 初始化为 0?在你知道它代表什么之前,你无法判断它是否坏了。

这是您可以对课程进行的更良性的更改之一。不同的更改(例如重新排序成员)肯定需要更改相关代码。

如果您确定永远不会更改数据的布局,您似乎只能安全地使用这样的聚合初始化。

或者,如果预计唯一的更改是可以进行值初始化的新成员。 (C 支持指定的初始值设定项,它们甚至可以适应成员顺序的变化。不幸的是,我们在 C++ 中没有它们。

或者,如果您认为查找和更新聚合初始化没有问题。您应该知道,只要您对聚合进行更改,这种可能性就存在。

但事实上,构造函数确实提供了一种“实现防火墙”,将用户与成员的更改分离开来。像新成员这样的一些更改可能会提示对构造函数的更改,但缺少构造函数参数确实有助于破坏编译。

那么有没有“永远不要在非同构结构上使用聚合初始化”的潜规则?

当然不是没有你我都考虑过的例外情况。此外,同质性与异质性没有区别。

我会反过来说,在设计 public API 时,应该考虑类的布局是否应该一成不变,或者改为将成员设为私有和提供构造函数。对于内部 API,如果您能快速完成该类的所有使用,这并不重要。


GCC 有一个警告选项,可以解决您描述的确切情况:-Wmissing-field-initializers(由-Wextra 启用)。如果您提供任何成员初始化器,但不是全部,它将生成警告。

【讨论】:

  • “不同的更改,例如重新排序成员,肯定需要更改相关代码。”我实际上正在重新排序 x 和 y,这是主要问题。也许添加 z 混淆了这个问题。我会将问题编辑为提及重新排序。
  • @JoeTaicoon 不要删除有关添加新字段的问题。这将使我的部分答案过时。但请随意添加有关重新排序的编辑。我的回答已经涵盖了这两种情况。
猜你喜欢
  • 1970-01-01
  • 2016-07-18
  • 2016-06-23
  • 1970-01-01
  • 2022-01-21
  • 2011-09-11
  • 2015-07-30
  • 2020-10-22
  • 2013-09-22
相关资源
最近更新 更多