C++ polymorphism实现报文处理器的raw pointer使用问题及优化咨询
问题解答
你提到的问题是真实存在的严重风险,当前代码能正常运行纯属巧合:
栈上分配的SyncPacket/TypeAPacket对象在离开if分支的作用域后就会被系统回收,curr_pkt此时会变成悬垂指针,后续所有通过这个指针的操作都属于C++标准定义的未定义行为,可能当前测试场景下栈内存没有被覆盖所以表现正常,但只要运行环境、代码逻辑稍有变动就可能出现乱码、崩溃等不可预期的问题,绝对不能在生产环境使用。
关于raw指针的使用
raw指针本身没有问题,但你的用法错了:raw指针不应该持有生命周期短于自身的对象的地址。如果你要保留多态对象的生命周期,要么延长对象的生命周期,要么改用堆分配+智能指针管理。
智能指针改造方案
最符合你现有多态设计的方案是使用std::unique_ptr管理报文对象,改造成本极低,且完全避免内存泄漏和悬垂指针问题,改造要点如下:
- 给基类
Packet添加虚析构函数,否则多态对象销毁时会出现内存泄漏 - 将
Parser的curr_pkt成员类型改为std::unique_ptr<Packet>,由它独占报文对象的所有权 - 识别到报文头时,用
std::make_unique在堆上创建对应子类的实例,赋值给curr_pkt,旧的报文对象会被自动销毁 - 修正原代码中第二个if分支判断条件错误的问题(原代码两个分支都判断了
SyncPacket::headerVal,永远不会创建TypeAPacket实例)
改造后的完整代码如下:
#include <memory> #include <vector> class Packet { public: virtual void parseByte(unsigned char byte) {} // 多态基类必须添加虚析构函数 virtual ~Packet() = default; }; class SyncPacket : public Packet { public: static const unsigned char headerVal = 0x0A; void parseByte(unsigned char byte) override { // 实现同步逻辑 } }; class TypeAPacket : public Packet { public: static const unsigned char headerVal = 0x0B; void parseByte(unsigned char byte) override { // 实现TypeA报文解码逻辑 } }; class Parser { private: std::unique_ptr<Packet> curr_pkt; public: void parsePacket(unsigned char byte) { if(byte == SyncPacket::headerVal) { curr_pkt = std::make_unique<SyncPacket>(); } else if(byte == TypeAPacket::headerVal) { curr_pkt = std::make_unique<TypeAPacket>(); } // 非空判断避免空指针访问 if (curr_pkt) { curr_pkt->parseByte(byte); } } }; int main() { std::vector<unsigned char> bytes; // 读入字节流 Parser pktParser; for(unsigned char byte: bytes) { pktParser.parsePacket(byte); } // Parser销毁时会自动释放curr_pkt持有的报文对象 }
如果你的所有报文类型都是固定且大小可控的,也可以使用std::variant存储报文对象,避免堆分配提升性能,但std::unique_ptr的方案和你现有设计匹配度最高,不需要修改上层调用逻辑,是最优选择。
内容的提问来源于stack exchange,提问作者jkang
相关产品推荐
相关产品推荐

