Возможна ли «сериализация без дублирования» в c ++ 0x? - PullRequest
2 голосов
/ 23 августа 2011

Одним из основных применений генерации кода в c ++ является поддержка сериализации сообщений.Как правило, вы хотите поддерживать указание содержимого и макета сообщения на одном шаге и создавать код для этого типа сообщения, который может дать вам объекты, которые можно сериализовать в / из потоков связи.В прошлом это обычно приводило к коду, который выглядит следующим образом:

class MyMessage : public SerialisableObject
{
  // message members
  int myNumber_;
  std::string myString_;
  std::vector<MyOtherSerialisableObject> aBunchOfThingsIWantToSerialise_;

public:
  // ctor, dtor, accesors, mutators, then:

  virtual void Serialise(SerialisationStream & stream)
  {
    stream & myNumber_;
    stream & myString_;
    stream & aBunchOfThingsIWantToSerialise_;
  }
};

Проблема с использованием этого вида дизайна заключается в том, что он нарушает важное правило хорошей архитектуры: вам не нужно указывать намерениедизайн дважды.Дублирование намерений, как дублирование кода и другие обычные дубликаты разработки, оставляет место для одного места в коде, чтобы расходиться с другим, вызывая ошибки.

В приведенном выше примере дублирование - это список членов.Потенциальные ошибки включают в себя добавление члена в класс, но забывание добавить его в список сериализации, сериализацию члена дважды (возможно, не используя тот же порядок, что и объявление члена или, возможно, из-за неправильного написания аналогичного члена, среди других способов)или сериализацию чего-то, что не является членом (что может привести к ошибке компилятора, если поиск по имени не найдет что-то в другой области видимости, чем объект, соответствующий правилам поиска).Такая ошибка - та же самая причина, по которой мы больше не пытаемся сопоставить каждое выделение кучи с удалением (вместо этого используя интеллектуальные указатели) или когда-либо открывать файл с закрытием (используя механизмы RAII ctor // dtor) - мы не хотим иметьчтобы соответствовать нашим намерениям в нескольких местах, потому что бывают случаи, когда мы - или другой инженер, менее знакомый с намерением - совершаем ошибки.

В общем, поэтому это было одной из тех вещей, о которых может позаботиться генерация кода,Вы можете создать файл MyMessage.cg, чтобы указать макет и элементы за один шаг

serialisable MyMessage
{
  int myNumber_;
  std::string myString_;
  std::vector<MyOtherSerialisableObject> aBunchOfThingsIWantToSerialise_;
};

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

Мне было интересно,это было возможно сделать в C ++ 0x без генерации внешнего кода.Существуют ли какие-либо новые языковые механизмы, позволяющие определить класс как сериализуемый один раз, а имена и расположение его членов используются для компоновки сообщения во время сериализации?

Чтобы было ясно, я знаю, что естьтрюки с буст-кортежами и слиянием, которые могут приблизиться к такому поведению даже на языке до-++ 0x.Однако эти способы использования, основанные на индексации в кортеже, а не на доступе по имени-члену, были хрупкими для изменения компоновки, поскольку другие места в коде, которые получают доступ к сообщениям, также должны были бы быть переупорядочены.Необходим некоторый доступ по имени-члену, чтобы не дублировать спецификацию макета в местах кода, которые используют сообщения.

Кроме того, я знаю, что было бы неплохо перейти к следующемууровень и попросить указать, когда некоторые члены не должны быть сериализованными.Другие языки, которые предлагают встроенную сериализацию, часто предлагают для этого какой-то атрибут, поэтому int myNonSerialisedNumber_ [[noserialise]];может показаться естественным.Тем не менее, я лично считаю плохим проектирование иметь сериализуемые объекты, в которых все не сериализовано, поскольку время жизни сообщений находится в транспортном уровне к / от уровня связи, отдельно от других времен жизни данных.Кроме того, у вас может быть объект, который имеет чисто сериализуемый как один из его членов, так что такая функциональность ни в коем случае не предлагает язык.

Возможно ли это?Или комитет по стандартам упустил такую ​​интроспективную возможность?Мне не нужно, чтобы это выглядело как файл кода gen выше - любой простой метод для определения компоновки и элементов компиляции во время компиляции за один шаг решит эту общую проблему.

Ответы [ 2 ]

2 голосов
/ 24 декабря 2012

Это возможно и практично в C ++ 11 - фактически это было возможно в C ++ 03, синтаксис был слишком громоздким.Я написал небольшую библиотеку, основанную на той же идее - см. Следующее:

www.github.com / molw5 / framework

Пример синтаксиса:

class Object : serializable <Object,
    value <NAME(“Field 1”), int>,
    value <NAME(“Field 2”), float>,
    value <NAME(“Field 3”), double>>
{
};

Большая часть базового кода может быть воспроизведена, в принципе, на C ++ 03 - некоторые детали реализации без шаблонов с переменными параметрами были бы ... сложными, но я считаю, что было бы возможно восстановить ядрофункциональность.То, что вы не могли воспроизвести в C ++ 03, это макрос NAME выше, и синтаксис довольно сильно зависит от него.Макрос предоставляет механизм, необходимый для генерации уникального typename из строки, а именно:

NAME(“Field 1”)

расширяется до

 type_string <'F', 'i', 'e', 'l', 'd', ' ', '1'>

посредством использования некоторых распространенных макросов и constexpr (для извлечения персонажа).Назад в C ++ 03 что-то похожее на type_string выше, должно быть введено вручную.

1 голос
/ 23 августа 2011

C ++ любой формы не поддерживает ни самоанализ, ни отражение (в той степени, в которой они различаются).

Одна приятная вещь при выполнении сериализации вручную (т.е. без самоанализа или отражения) состоит в том, что вы можете предоставить объекту управление версиями Вы можете поддерживать старые формы сериализации и просто создавать разумные значения по умолчанию для данных, которых не было в старых версиях. Или, если новая версия удаляет некоторые данные, вы можете просто сериализовать и удалить их.

Мне кажется, что вам нужна Boost.Serialization.

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