Заполните список CapnProto не примитивным
Согласно документации CapnProto: (ПРИМЕЧАНИЕ: я использую версию C++)
Для List, где Foo является не примитивным типом, тип, возвращаемый operator[] и iterator::operator*(): Foo::Reader (для List::Reader) или Foo::Builder (для List::Builder), Метод set компоновщика принимает Foo:: Reader в качестве второго параметра.
Хотя использование "set" работает нормально для не примитивных типов: Другой вопрос переполнения стека только для примитивов
Похоже, что нет функции set для автоматически генерируемых списков не примитивов. Произошел ли сбой в создании моего CapnProto каким-то образом, или есть другой способ установки элементов в списке не примитивов?
1 ответ
Есть метод "set", но он называется setWithCaveats()
:
destListBuilder.setWithCaveats(index, sourceStructReader)
Это сделано для того, чтобы вы знали, что существуют некоторые неясные проблемы с настройкой элемента списка структуры. Проблема связана с тем фактом, что структурные списки не представлены в виде списка указателей, как вы могли бы ожидать, а скорее представляют собой "сплющенную" серию последовательных структур, все одного размера. Это означает, что пространство для всех структур в списке выделяется во время инициализации списка. Итак, когда вы звоните setWithCaveats()
целевое пространство уже выделено ранее, и вы копируете исходную структуру в это пространство.
Это создает проблему при наличии разных версий: структура источника могла быть создана с использованием более новой версии протокола, в которой были определены дополнительные поля. В этом случае он может быть больше ожидаемого. Но место назначения уже было выделено на основе версии протокола, с которой вы скомпилировали. Итак, он слишком маленький! К сожалению, нет другого выбора, кроме как отказаться от вновь определенных полей, о которых мы не знаем. Следовательно, данные могут быть потеряны.
Конечно, может случиться так, что в вашем приложении вы знаете, что значение структуры не берется из более новой версии, или что вам все равно, если вы потеряете поля, о которых не знаете. В этом случае, setWithCaveats()
будет делать то, что вы хотите.
Если вы хотите быть осторожным, чтобы сохранить неизвестные поля, вы можете посмотреть на метод capnp::Orphanage::newOrphanConcat()
, Этот метод может объединить список списков читателей структуры в один список таким образом, чтобы данные не терялись - целевой список выделяется с размером каждой структуры, равным максимуму всех входных структур.
auto orphanage = Orphanage::getForMessageContaining(builder);
auto orphan = orphanage.newOrphanConcat({list1Reader, list2Reader});
builder.adoptListField(kj::mv(orphan));