Добавить участника в существующую структуру без нарушения устаревшего кода
В некотором устаревшем коде, с которым я работаю, существует следующее определение.
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
?
Ответы
Ответ 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;
}
}
а затем вы будете ясны и понятны о том, когда вы используете что - и перенести вещи, когда вам нужно.