Copying a generic protobuf into a new object on the heap

11,808

This is correct.

If you want type safety a little template magic can help:

template<class Msg, 
         std::enable_if_t<std::is_base_of<protobuf::Message,
                                          Msg>::value>>
std::unique_ptr<Msg> clone(const Msg* msg)
{
  std::unique_ptr<Msg> p(msg->New());
  p->CopyFrom(*msg);
  return p;
}

And you'll see that I have wrapped the protocol buffers object in a unique_ptr. This provides some exception safety and has the added advantage of being convertible to shared_ptr.

Why is this a good idea? Well, consider a protocol buffer object called Foo that has 2 string members called bar and baz:

void test(const Foo* source_foo)
{
  // clone and convert the unique_ptr to shared_ptr
  std::shared_ptr<Foo> myclone(clone(source_foo));

  myclone->bar() += " cloned";
  myclone->baz() += " cloned again";

  // get a shared_ptr to the members:
  auto mybar = std::shared_ptr<const std::string>(myclone, &myclone->bar());
  auto mybaz = std::shared_ptr<const std::string>(myclone, &myclone->baz());

  give_away(mybar);
  do_something_else(mybaz);

  // at this point the use_count of myclone is at least 3. 
  // if give_away results in holding on to the shared_ptr 
  // to string then myclone will be kept 
  // alive until the last shared_ptr goes away 

}
Share:
11,808
Petr
Author by

Petr

Updated on June 16, 2022

Comments

  • Petr
    Petr almost 2 years

    I want to make a copy of a generic const protobuf Message for further manipulation. I came up with

    Message* myfn(const Message *msg) {
      Message *copy = msg->New();
      copy->CopyFrom(*msg);
      // do stuff
      return copy;
    }
    

    Is this correct/idiomatic? Or is there a better way (perhaps C++11 specific)?