提问人:klonyyy 提问时间:9/23/2023 最后编辑:klonyyy 更新时间:9/23/2023 访问量:63
具有访客模式和静态内存分配的持久配置
Persistent config with visitor pattern and static memory allocation
问:
我正在为嵌入式项目准备一个持久配置模块。我想使用通过访客模式实现的序列化:
struct softwareInfo
{
uint32_t version;
std::array<uint8_t, 40> commitHash;
uint32_t buildDate;
template <class T>
void pack(T& archive)
{
archive.process(version);
archive.process(commitHash);
archive.process(buildDate);
}
};
当涉及到存储模块时,我想像这样注册每个结构:
PersistentConfig conf{};
conf.register(&softwareInfo, "swinfo");
conf.register(&foo, "foo");
然后执行写入或读取函数,该函数获取所有已注册的对象,并序列化或反序列化它们以执行写入或读取操作。同时写入它们更方便,因为我无法写入事先未擦除的 FLASH,并且最小擦除大小为单页 (2048B)。
由于它是一个嵌入式项目,我想避免动态分配,如果没有它,我在实现类时会遇到麻烦。我想象它包含一个指向某些指针的数组,我可以将结构注册到这些指针:PersistentConfig
persistentEntry
struct persistentEntry
{
EntryBase* object;
std::string_view name;
uint32_t size;
uint32_t datacrc32;
};
std::array<persistentEntry, maxEntries> entries;
我想创建一个 EntryBase 类,然后创建一个模板化的派生类,该类可以保存指向任何类型的已注册对象的指针:
class EntryBase
{
public:
virtual ~EntryBase() {}
virtual bool pack(serializer::Packer& packer) = 0;
virtual bool pack(serializer::Unpacker& unpacker) = 0;
};
template <typename T>
class Entry : public EntryBase
{
public:
explicit Entry(T* item) : item(item)
{
}
bool pack(serializer::Packer& packer) override
{
return item->pack(packer);
}
bool pack(serializer::Unpacker& unpacker) override
{
return item->pack(unpacker);
}
T* const item;
};
但是我需要在register事件期间在堆上创建Entry:
template <class PackableObject>
bool registerEntry(PackableObject* obj, const std::string_view& name)
{
entries.at(numberOfEntries).object = new Entry<PackableObject>(obj); //I'd like to avoid that
entries.at(numberOfEntries).name = name;
entries.at(numberOfEntries).hashName = Checksum::crc32(name.data(), name.size());
return ++numberOfEntries > maxEntries;
}
我还想到只保留指向函数的指针,但由于它也模板化了,因此它无法正常工作。pack
有没有办法在不需要动态分配对象的情况下保存已注册的结构指针?或者我应该坚持使用此解决方案,只创建一个可以安全分配的固定内存池?Entry
答:
0赞
Jarod42
9/23/2023
#1
有没有办法保存已注册的结构指针,而无需动态分配 Entry 对象?
您仍然可以放置 new,特别是因为所有派生类只有一个指针作为成员。
struct persistentEntry
{
aligned_storage_t<sizeof(Entry<void>), alignof(Entry<void>)> buffer;
EntryBase* object;
std::string_view name;
uint32_t size;
uint32_t datacrc32;
template <class PackableObject>
void init(PackableObject* obj, const std::string_view& name) {
static_assert(sizeof(Entry<PackableObject>) <= sizeof(buffer));
object = new (&buffer) Entry<PackableObject>(obj);
this->name = name;
datacrc32 = Checksum::crc32(name.data(), name.size());
}
void deinit() {
object.~EntryBase();
}
};
另一种方法是模仿 vtable:
template <typename T>
bool packT(void* object, serializer::Packer& packer)
{
reurn reinterpret_cast<T*>(object)->pack(packer);
}
template <typename T>
bool unpackT(void* object, serializer::Unpacker& unpacker)
{
reurn reinterpret_cast<T*>(object)->pack(unpacker);
}
struct persistentEntry
{
void* object = nullptr;
bool (*pack)(void* object, serializer::Packer& packer) = nullptr;
bool (*unpack)(void* object, serializer::Unpacker& unpacker) = nullptr;
std::string_view name;
uint32_t size;
uint32_t datacrc32;
template <class PackableObject>
void init(PackableObject* obj, const std::string_view& name) {
object = obj;
pack = &packT<PackableObject>;
unpack = &unpackT<PackableObject>;
this->name = name;
datacrc32 = Checksum::crc32(name.data(), name.size());
}
bool call_pack(serializer::Packer& packer) { return pack(obj, packer); }
bool call_pack(serializer::Unpacker& unpacker) { return unpack(obj, unpacker); }
};
上一个:访客模式序列化内存膨胀
下一个:语言翻译注释处理
评论
google::protobuf
Entry
MessageLite::New
MessageLite::CheckTypeAndMergeFrom