Канонический ответ: std::optional
.Это семантически точный способ выражения значения, которое может существовать или не существовать в модели.
При создании такой модели для каждого необязательного поля в схеме вы генерируете соответствующую запись std::optional
в оболочке,Затем при десериализации вы можете использовать std::none
, чтобы отметить отсутствующую запись, и при обращении к ней клиентский код должен проверить наличие фактического значения 1 .
Если ваши объекты большие, и вы хотите избежать ненужного хранения пустого пространства 2 , следующая альтернатива - std::unique_ptr
.Недостатком является наличие семантики указателя, но в остальном он остается действительным инструментом для такого случая.
Если элементы очень динамические, например, возможный набор составляет десятки или сотни, нотипичное использование увидят лишь немногие, хранилище значений ключей (например, std::map
) может быть лучшей идеей;тогда вы можете хранить только один тип значения.Это может быть немного смягчено с помощью std::variant
, используемого в качестве типа значения карты, который дает вам одну из многих возможностей, или std::any
, который может эффективно удерживать что угодно, в то же время теряя безопасность типов.
Решение будетв конечном итоге зависит от вашей точной модели и характеристик использования.
1 Если клиентский код ожидает T
, а доступ к полю дает им optional<T>
, этап развертываниябудет / должен проверить наличие фактического значения.Это основная причина использования optional
.
2 sizeof(optional<S>)
чаще всего будет sizeof(S) + 1
, но может увеличиться из-за правил выравнивания. Производительность и память * В разделе 1039 * этой статьи это прекрасно показано.