Search code examples
c++protocol-buffersabstract-classsmart-pointers

How to return google protocol messages from factory as unique_ptr?


I am still trying to understand how to use the Google Protocol Buffers library so I hope you will excuse my ingorance if this is off topic.

I want to wrap the Google Proto Factory such that the message types are placed in unique_ptrs so I don't have to worry about the memory management.

This is what I have:

  ProtoBufFactory::ProtoBufFactory() {
      Anon::Protocol_descriptor();
      Auth::Protocol_descriptor();
      m_factory = ::google::protobuf::MessageFactory::generated_factory();
    }

    //https://stackoverflow.com/questions/29960871/protobuf-message-object-creation-by-name
    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);
    }

I'm getting an error indicating that I cannot do this because I am operating on an abstract type.

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;

I am confused by this error message. There is a reddit post where a similar error was reported unrelated to google protobuf: https://www.reddit.com/r/cpp_questions/comments/goa2he/stdunique_ptr_stdmake_unique_and_abstract_classes/

that seems to be because child classes were missing implementations of the abstract class. I thought it might be a linker problem but from what I can tell I'm linking the C++ protobuf generated files.

I'm not quite sure how best to proceed with this or even if unique_ptrs are all that beneficial in this circumstance.

I was hoping that there was an easy way to create a unique_ptr to the Google protocol buffer messages so I do not have to worry about explicitly deleting them.


Solution

  • std::make_unique is misnamed. It should be std::emplace_unique_ptr.

    It both creates the object and allocates space for it and stores it in a smart pointer.

    As you already have an object and space for it, you don't use make_unique:

    return std::unique_ptr<::google::protobuf::Message>(mutable_msg);
    

    but instead just make a unique_ptr wrapping the pointer.