-
Notifications
You must be signed in to change notification settings - Fork 15.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generated move constructors marked as noexcept, but may throw exceptions #3630
Comments
I'm very sorry, I must've been looking at an old version of the library. The experimental version of move support ( However, I noticed a problem with how this feature is implemented. Even though these two functions are marked
If move constructing from a message with an arena, or move assigning between objects with different arenas, then I am not sure what the solution to this is. I am a bit confused about the implementation in the first place: surely if you move construct (or indeed copy construct) from an arena-based message, then you usually want the new object to use the same arena? A move constructor implemented that way really would never throw exceptions. (The move assignment operator would still be a lost cause, but removing its |
This is partly a result of our Google C++ Style Guide where exceptions are not allowed: So in Google code base, throwing an exception equals program termination. Therefore marking protobuf move constructors noexcept has no negative consequences even if they may actual throw. I don't really have a great answer here. The movable operator= can't assume the two message are from the same arena because we do have use cases where they are from different arenas. It seems to me the CopyFrom() call is inevitable. To make code work correctly with the presence of exceptions, the only solution I can think of is to remove the noexcept annotation... |
I suggest that for the move assignment, it is probably fine to just remove For the move constructor, I think Option 1: When move constructing a message, force the destination message to use the same arena as the source. This means the move can be implemented as a simple swap (see note below) even for objects with an arena. This would possibly be quite a big change, in two related respects:
Option 2: Make it undefined behaviour to move from a message with an arena (with These two options apply equally well to move constructors for Note about simple swap: The only worry I can think of here is making sure that the moved-from object still has a reference to the arena. If the arena is in some separately-allocated |
Protobuffers doesn't throw exceptions. Throwing an exception is equivalent to aborting for us, so if any part (for instance new) throws in the proto library, you should see protos as inconsistent and only aborting is defined. Given this semantics adding noexcept is correct. Furthermore move-semantics is only useful with noexcept otherwise containers will not use move, so we can't remove noexcept. Arguably noexcept should be added to ALL proto functions so that abortion is guaranteed instead of continuing with a inconsistent proto system which can't even be cleaned up. |
As discussed in #2791, generated message classes have recently been given move constructors and move assignment operators.
However, they are not marked[Edit: Sorry, they are markednoexcept
. This means that they are not used in standard containers in situations where it would be desirable.noexcept
, so the complaint below does not apply. However, I believe they are incorrectly markednoexcept
; see the comment below.]Consider the following example snippet:
Thanks to the new move constructor, on line 2 it is guaranteed that the copy constructor of MyMsg will not be invoked; instead, the move constructor will be used by the
push_back()
method for the"a"
message. Again, on line 3, thepush_back()
method will use the move constructor on the"b"
message to add it to the vector. However, if there is not enough capacity to fit the"b"
message then the vector will first reallocate it members, and at this point it will use the copy constructor on the"a"
message. This is because it is impossible to perform reallocation in a way that provides the strong exception guarantee by using a move constructor that might throw an exception. Search the web forstd::move_if_noexcept
for more information.In my opinion, this is an important use case of move constructors, and I think many people would be surprised to see the copy constructor invoked in the above snippet. I don't see any harm in marking these functions
noexcept
because there really is no way for them to throw exceptions, and they are only included when the compiler is known to be C++11 compliant.The text was updated successfully, but these errors were encountered: