如何从Google Protocol Buffers工厂返回unique_ptr包装的消息?
问题:用unique_ptr管理Protobuf消息时的抽象类错误
我仍在学习使用Google Protocol Buffers库,若问题偏离主题还请见谅。我希望封装Google Proto工厂,将生成的消息类型放入unique_ptr中以避免手动内存管理。以下是我的代码:
ProtoBufFactory::ProtoBufFactory() { Anon::Protocol_descriptor(); Auth::Protocol_descriptor(); m_factory = ::google::protobuf::MessageFactory::generated_factory(); } // 意图通过消息描述符创建Protobuf消息并用unique_ptr管理 std::unique_ptr<::google::protobuf::Message> ProtoBufFactory::create(const ::google::protobuf::Descriptor * msg_descriptor) { const ::google::protobuf::Message * prototype_msg = m_factory->GetPrototype( msg_descriptor ); if (prototype_msg == nullptr) { EXCEPT(1, "Cannot create prototype message from message descriptor"); } ::google::protobuf::Message * mutable_msg = prototype_msg->New(); if (mutable_msg == NULL) { EXCEPT(1, "Failed in prototype_msg->New(); to create mutable message"); } return std::make_unique<::google::protobuf::Message>(mutable_msg); }
编译时遇到错误,提示无法操作抽象类型:
error: invalid new-expression of abstract class type ‘google::protobuf::Message’ 857 | { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); } /include/google/protobuf/message.h:235:23: note: because the following virtual functions are pure within ‘google::protobuf::Message’: 235 | class PROTOBUF_EXPORT Message : public MessageLite { | ^~~~~~~ /usr/local/include/google/protobuf/message.h:244:12: note: ‘virtual google::protobuf::Message* google::protobuf::Message::New() const’ 244 | Message* New() const override = 0; /usr/local/include/google/protobuf/message_lite.h:465:15: note: ‘virtual int google::protobuf::MessageLite::GetCachedSize() const’ 465 | virtual int GetCachedSize() const = 0; /usr/local/include/google/protobuf/message.h:367:20: note: ‘virtual google::protobuf::Metadata google::protobuf::Message::GetMetadata() const’ 367 | virtual Metadata GetMetadata() const = 0;
我对该错误感到困惑,曾看到类似问题是因子类未实现抽象类方法,但我已链接了C++ protobuf生成文件。我不确定该如何推进,也不确定在此场景下使用unique_ptr是否有益,希望能找到简便方法用unique_ptr管理Google Protocol Buffers消息,无需手动删除。
解决方案
错误原因
你调用std::make_unique<::google::protobuf::Message>(mutable_msg)的行为是错误的:Message是抽象基类(包含纯虚函数),无法直接实例化。而prototype_msg->New()已经返回了一个具体子类(你定义的Anon/Auth等消息类)的指针,你不需要再用make_unique去构造基类对象,只需把这个现成的指针交给unique_ptr接管即可。
修正后的代码
std::unique_ptr<::google::protobuf::Message> ProtoBufFactory::create(const ::google::protobuf::Descriptor * msg_descriptor) { const ::google::protobuf::Message * prototype_msg = m_factory->GetPrototype( msg_descriptor ); if (prototype_msg == nullptr) { EXCEPT(1, "Cannot create prototype message from message descriptor"); } ::google::protobuf::Message * mutable_msg = prototype_msg->New(); if (mutable_msg == nullptr) { EXCEPT(1, "Failed in prototype_msg->New(); to create mutable message"); } // 直接将子类指针交给unique_ptr,利用多态特性安全管理 return std::unique_ptr<::google::protobuf::Message>(mutable_msg); // 更简洁的写法:return {mutable_msg}; }
关键说明
- unique_ptr的合理性:完全适合管理Protobuf消息。
unique_ptr<Message>可以安全持有子类指针,且Protobuf的Message基类析构函数是虚函数,销毁时会自动调用子类的析构逻辑,不会产生内存泄漏,完美替代手动delete。 - 错误本质:和链接生成文件无关,是代码逻辑错误——试图实例化抽象基类,而非子类未实现方法。
- 额外优化:如果使用C++14及以上,也无法用
make_unique直接构造抽象类实例,这里New()已经帮你创建了具体实例,直接接管指针是最优解。
内容的提问来源于stack exchange,提问作者user2267258
相关产品推荐
相关产品推荐

