9

I've checked the move constructor spec and a Message constructor source and didn't find one.

If there's not, does anyone know about a plan to add it?

I'm using proto3 syntax, writing a library and considering between return through value vs unique_ptr.

Paweł Szczur
  • 5,078
  • 2
  • 26
  • 30
  • 1
    When this was [discussed in the mailing list](https://groups.google.com/forum/#!topic/protobuf/QdHPjwmUgXw), someone attached a protoc generator plugin they had written to add move constructor support. They called it protoc-gen-cxx11, but unfortunately I can't find it anywhere. – Jim Oldfield May 28 '15 at 11:41

3 Answers3

10

According to https://github.com/google/protobuf/issues/2791 this will be supported in Protobuf version 3.4.0.

Daniel Schepler
  • 2,673
  • 11
  • 19
8
  1. If you try to use a assignment operator, RVO will do optimization to prevent an extra copy.

    // RVO will bring the return value to a without using copy constructor.
    SomeMessage a = SomeFooWithMessageReturned();
    
  2. If you want to use std::move to move a lvalue into a list/sub message, etc. Try to use ConcreteMessage::Swap method. The swapped item will be useless.

    // Non-copy usage.
    somemessage.add_somerepeated_message()->Swap(&a);
    somemessage.mutable_somesinglar_message()->Swap(&a);
    // With message copying
    somemessage.add_somerepeated_message()->CopyFrom(a);
    *somemessage.mutable_somesinglar_message() = a;
    
Alexander Chen
  • 182
  • 1
  • 9
  • 1
    Thank you very much for noting about `Swap` method. Move assignment for protobuf objects may be emulated by using the next function: `template static void pb_move_assign(Protobuf &to, Protobuf &&from) { from.Swap(&to); from.Clear(); }` – anton_rh May 24 '16 at 12:17
  • @anton_rh The Clear() isn't necessary; it's not guaranteed what state the `from` object will be in after a move (except that it's a legal state) e.g. a short std::string might well have its original value after a move. So you really might as well just call Swap() directly rather than a wrapper function. – Arthur Tacca May 10 '17 at 13:59
4

As of version 2.6.1, C++ protobuf compiler generates only copy constructors and copy assignment operators. But if your compiler supports return value optimization (and the conditions for it are satisfied) the copy constructor won't be called anyway.

You can add some printing statements into generated code of your messages' copy constructors to see if they are really invoked or not. You can also do it by writing a protoc plugin, so it persists between protoc invocations.

Community
  • 1
  • 1
Anton Savin
  • 38,277
  • 8
  • 49
  • 82
  • 3
    It's actually surprisingly hard to ensure that RVO is used in all the cases you expect it, since the compiler is not required to use it and compilers aren't always very smart about deciding whether they can use it. You basically have to make sure that your function has only _one_ return statement (returning a local variable). Also there are lots of other situations where you want move-like semantics in practice, though some of them can be covered by careful use of swap(). – Kenton Varda May 20 '15 at 19:30
  • 2
    Obviously the RVO won't help you if want something like a vector of large message objects. A work around is to use a vector of unique_ptr's to messages, but this is a notational annoyance and it means your source functions must return unique_ptrs to avoid copying elsewhere, so the workaround can infect a lot of code. – Jim Oldfield May 28 '15 at 11:20
  • @JimOldfield Instead of a `std::vector>`, you could use the protobuf container `google::protobuf::RepeatedPtrField`. This class is used in repeated fields but it's fine to use it for other purposes. It uses pointers internally but the iterators point directly to the messages so you don't need to double dereference. As per Daniel Schepler's answer, neither workaround will be necessary as of protobuf 3.4. – Arthur Tacca Aug 19 '17 at 12:38
  • The remark of 3.6.1 differs from the protobuf changlelog which added move to most objects in 3.4, a few more (array types) in 3.5, and turned off the guards to CXX features in 3.6 https://github.com/protocolbuffers/protobuf/blob/master/CHANGES.txt In particular, 3.4 has the "Following C++11 features are introduced when C++11 is available": - move-constructor and move-assignment are introduced to messages - Repeated fields constructor now takes std::initializer_list – RyanD Mar 07 '19 at 14:32