开发者

Add member to existing struct without breaking legacy code

There is the following definition in some legacy code that I am working with.

struct VlanData
{
    uint16_t mEtherType;
    uint16_t mVlanId;
};

I want to add a new member to this struct:

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

However, use of VlanData has been fairly inconsistent through the legacy code.

Not initialized on construction:

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

Value initialized:

VlanData myVlans = { 0x8100, 100 };

What I want to do is come up with a safe way to ensure that `mVlanPriority' is automatically set to 0 in legacy code without updating a lot of code.

I understand I could modify the legacy code to value-initialize all members like so:

VlanData myVlans = {};

But I don't want to have to update all of this code. I believe that creating a def开发者_StackOverflow中文版ault constructor like this would help:

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

But this would also destroy the POD-ness of the struct.

So I guess I have several questions:

  1. Is there a safe way I can ensure that mVlanPriority is set to 0 in legacy code without updating the legacy code?
  2. What use of the class would break if this was no longer a POD type?


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;
 };

Define other kinds of operators and add type conversion functions as you need.

eg:

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


Is there a safe way I can ensure that mVlanPriority is set to 0 in legacy code without updating the legacy code?

No there is no standard way in current standard. You must have to have constructor.

What use of the class would break if this was no longer a POD type?

As @junjanes has mentioned in the comments, your code will be broken where you try to initialize the members with brackets.

Edit: To address your problem, I would suggest

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)
  {}
};

So now, your new variable will be initialized to 0 and you have to do a very less typing for fixing compilation error.

Change,

VlanData myVlans = { 0x8100, 100 };

To,

VlanData myVlans( 0x8100, 100 );


I'm not an expert on c++0x, but I do know that the strict pod-ness guarentees were relaxed in c++0x, with the introduction of a standard-layout class. Your class with a constructor isn't pod but I believe it is standard-layout and so it might be worth checking your compilers compatability with this aspect of the new standard. I think the problems that you are having were fixed up quite a lot with c++0x.

I also believe that curly bracket initialization of standard layout classes is also allowed in c++0x. See the Initializer lists and Uniform initialization section of this wikipedia article.

Looking up what the standard-layout class fixes should give a fairly good list as to what can break for non-pod types in the current standard. For instance, reinterpret_cast is not safe in c++03 for non-pod types (the alignment might not be correct) but is safe in c++0x for standard-layout classes.

In short, I think your frustrations are well recognised and perhaps even ironed out in the new standard, but I don't think its going to possible to fix them all with the current standard.

My approach would be to try an leave legacy code untouched and slowly migrate to the new version of your class:

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;
  }
}

and then you are explicit and clear as to when you are using what - and migrate things when you need to.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜