无默认构造函数时,如何用QDataStream反序列化std::map?
解决无默认构造函数的自定义类的std::map序列化/反序列化问题
嘿,这个问题我之前也踩过坑!核心矛盾就是MyClass没有默认构造函数,没法像普通类那样先声明对象再赋值。咱们一步步来拆解解决方案:
为什么malloc的方式行不通?
你用malloc分配内存的思路是错的——malloc只会给你一块原始内存,根本没有调用MyClass的构造函数,这时候*im是一个完全未初始化的无效对象,插入std::pair时自然会报错,甚至会导致未定义行为,绝对不能这么干!
正确的解决思路:直接构造对象,避免默认构造
我们的目标是跳过默认构造的步骤,直接用从QDataStream读取到的数据构造MyClass对象,然后插入map。这里有两种常用方案:
方案1:给MyClass写一个静态反序列化方法
先给MyClass添加一个静态方法,专门负责从QDataStream读取数据并构造对象:
class MyClass { // 假设你的MyClass有一个带参数的构造函数 public: MyClass(QString name, int value) : m_name(std::move(name)), m_value(value) {} // 静态反序列化方法 static MyClass fromDataStream(QDataStream& in) { QString name; int value; // 按序列化的顺序读取数据 in >> name >> value; // 直接用读取到的数据构造对象并返回 return MyClass(std::move(name), value); } private: QString m_name; int m_value; };
然后修改map的反序列化运算符,直接调用这个静态方法构造对象并插入:
QDataStream& operator>>(QDataStream& in, std::map<QString, MyClass>& i){ quint32 mapSize; in >> mapSize; i.clear(); QString key; while(mapSize--){ in >> key; // 直接构造MyClass并插入map,用emplace更高效 i.emplace(std::move(key), MyClass::fromDataStream(in)); } return in; }
方案2:直接在map反序列化中读取参数并构造
如果不想给MyClass加静态方法,也可以直接在map的反序列化逻辑里读取MyClass的构造参数,然后直接构造对象插入:
QDataStream& operator>>(QDataStream& in, std::map<QString, MyClass>& i){ quint32 mapSize; in >> mapSize; i.clear(); QString key; while(mapSize--){ in >> key; // 先读取MyClass构造需要的所有数据 QString className; int classValue; in >> className >> classValue; // 用std::make_pair或者emplace直接构造对象插入 i.insert(std::make_pair(std::move(key), MyClass(std::move(className), classValue))); // 或者用emplace更高效,避免多余拷贝 // i.emplace(std::move(key), std::move(className), classValue); } return in; }
额外注意点
- 序列化和反序列化的数据顺序必须完全一致,比如你序列化时先写
elem.first再写elem.second的成员,反序列化时就要按同样的顺序读取 - 推荐用
emplace代替insert,因为emplace可以直接在map的内存中构造对象,避免额外的拷贝或移动操作,性能更好
内容的提问来源于stack exchange,提问作者trablazar
相关产品推荐
相关产品推荐

