在不破坏旧代码的情况下,将成员添加到现有结构中

Add member to existing struct without breaking legacy code

本文关键字:添加 成员 结构 代码 情况下      更新时间:2023-10-16

在我使用的一些遗留代码中有以下定义。

struct VlanData
{
    uint16_t mEtherType;
    uint16_t mVlanId;
};

我想向这个结构添加一个新成员:

struct VlanData
{
    uint16_t mEtherType;
    uint16_t mVlanId;
    uint8_t mVlanPriority; // New member
};

然而,在遗留代码中,VlanData的使用相当不一致。

构造时未初始化:

VlanData myVlans;
myVlans.mEtherType = 0x8100;
myVlans.mVlanId = 100;

初始化的值:

VlanData myVlans = { 0x8100, 100 };

我想做的是想出一种安全的方法,确保"mVlanPriority"在旧代码中自动设置为0,而不更新大量代码。

我知道我可以修改遗留代码以值初始化所有成员,如下所示:

VlanData myVlans = {};

但我不想更新所有这些代码。我相信创建这样的默认构造函数会有所帮助:

VlanData()
: mEtherType(0),
  mVlanId(0),
  mVlanPriority(0)
{}

但这也会破坏结构的POD性。

所以我想我有几个问题:

  1. 有没有一种安全的方法可以确保mVlanPriority在不更新旧代码的情况下在旧代码中设置为0
  2. 如果这不再是POD类型,那么类的什么用途会被破坏
struct VlanData {
    struct P
    {
        uint8_t operator=(uint8_t v) { mVlanPriority = v; }
        uint8_t mVlanPriority; P() { mVlanPriority = 0; };
    };
    uint16_t mEtherType;
    uint16_t mVlanId;
    P mVlanPriority;
 };

定义其他类型的运算符,并根据需要添加类型转换函数。

例如:

int main(int argc, char** argv)
{
    VlanData myVlans0 = { };
    VlanData myVlans = { 0x8100, 100 };
    myVlans.mVlanPriority = 10;
}

有没有一种安全的方法可以确保mVlanPriority在中设置为0遗留代码而不更新遗留代码?

不,在当前的标准中没有标准的方法。你必须有构造函数。

如果这不再是POD类型,那么类的什么用途会被破坏?

正如@junjanes在评论中提到的那样,当你试图用括号初始化成员时,你的代码会被破坏。

编辑:为了解决您的问题,我建议

struct VlanData
{
  uint16_t mEtherType;
  uint16_t mVlanId;
  uint8_t mVlanPriority; // New member
  VlanData(uint16_t ether, uint16_t id, uint8_t priority = 0) :
           mEtherType(ether), mVlanId(id), mVlanPriority(priority)
  {}
};

因此,现在,您的新变量将被初始化为0,并且您必须执行非常少的类型来修复编译错误。

更改,

VlanData myVlans = { 0x8100, 100 };

收件人,

VlanData myVlans( 0x8100, 100 );

我不是c++0x方面的专家,但我确实知道,随着standard-layout类的引入,严格的pod保密性在c++0x中得到了放松。您的带有构造函数的类不是pod,但我相信它是standard-layout,因此可能值得检查编译器与新标准这一方面的兼容性。我认为你遇到的问题已经用c++0x解决了很多。

我还相信在c++0x中也允许对标准布局类进行花括号初始化。请参阅这篇维基百科文章的Initializer listsUniform initialization部分。

查找标准布局类的修复应该会给出一个相当好的列表,说明在当前标准中,非pod类型可以破坏什么。例如,对于非pod类型(对齐方式可能不正确(,repret_cast在c++03中是不安全的,但对于标准布局类,在c++0x中是安全的。

简言之,我认为你的沮丧情绪在新标准中得到了很好的认可,甚至可能得到解决,但我认为不可能用现行标准来解决所有这些问题。

我的方法是尝试保持遗留代码不变,然后慢慢迁移到类的新版本:

namespace version_1_1
{
  struct VlanData
  {
      uint16_t mEtherType;
      uint16_t mVlanId;
      uint8_t mVlanPriority; // New member
  };
  vlanData 
  convert_VlanData( ::VlanData const& v)
  {
     VlanData v2 = {v.mEtherType,v.mVlanId, 0};
     return v2;
  }
}

然后你就可以明确地知道什么时候使用什么,并在需要的时候迁移东西。