Добавить член в существующую структуру, не нарушая устаревший код - PullRequest
12 голосов
/ 19 июля 2011

В некотором устаревшем коде, с которым я работаю, есть следующее определение.

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 типа?

Ответы [ 3 ]

5 голосов
/ 19 июля 2011
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;
}
1 голос
/ 19 июля 2011

Есть ли безопасный способ убедиться, что 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 );
0 голосов
/ 19 июля 2011

Я не эксперт по c ++ 0x, но я знаю, что строгие гарантии pod -ness были ослаблены в c++0x с введением класса standard-layout.Ваш класс с конструктором не pod, но я считаю, что это standard-layout, и поэтому, возможно, стоит проверить совместимость ваших компиляторов с этим аспектом нового стандарта.Я думаю, что проблемы, с которыми вы сталкивались, были достаточно исправлены с c++0x.

Я также считаю , что инициализация фигурных скобок стандартных классов макета также разрешена в c ++ 0x,См. Initializer lists и Uniform initialization раздел этой статьи Википедии.

Поиск того, что исправления класса стандартной компоновки должны дать довольно хороший список того, что может сломаться длятипы стручков в текущем стандарте.Например, reinterpret_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;
  }
}

, а затем вы четко и ясно указываете, когда вы используете что - и переносите вещикогда вам нужно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...