Подтвердить что ты не робот

Добавить участника в существующую структуру без нарушения устаревшего кода

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

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 -ность структуры.

Итак, у меня есть несколько вопросов:

  • Есть ли безопасный способ гарантировать, что mVlanPriority установлен в 0 в устаревшем коде без обновления устаревшего кода?
  • Какое использование класса будет нарушено, если это уже не тип POD?
4b9b3361

Ответ 1

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

Ответ 2

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

Ответ 3

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

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

Взгляд на то, что исправления класса стандартного макета должны дать довольно хороший список того, что может сломаться для типов non-pod в текущем стандарте. Например, reinterpret_cast небезопасен в С++ 03 для типов non-pod (выравнивание может быть неправильным), но безопасно в С++ 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;
  }
}

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