diff --git a/doc/vs-cpp-protos.md b/doc/vs-cpp-protos.md index bcc8bcd1d2..5d30c54a84 100644 --- a/doc/vs-cpp-protos.md +++ b/doc/vs-cpp-protos.md @@ -56,12 +56,12 @@ no dangling pointers by performing automatic copies in some cases (for example `a->set_allocated_b(b)`, where `a` and `b` are on different arenas). C++'s arena object itself `google::protobuf::Arena` is **thread-safe** by -design, which allows users to allocate from multiple threads simultaneously with -no synchronization. The user can supply an initial block of memory to the -arena, and can choose some parameters to control the arena block size. The user -can also supply block alloc/dealloc functions, but the alloc function is -expected to always return some memory. The C++ library in general does not -attempt to handle out of memory conditions. +design, which allows users to allocate from multiple threads simultaneously +without external synchronization. The user can supply an initial block of +memory to the arena, and can choose some parameters to control the arena block +size. The user can also supply block alloc/dealloc functions, but the alloc +function is expected to always return some memory. The C++ library in general +does not attempt to handle out of memory conditions. ### upb @@ -92,9 +92,8 @@ message with one that may be on a different arena. unpredictability into the library. upb benefits from having a much simpler and more predictable design. * Some of the complexity in C++'s hybrid model arises from the fact that arenas - were added after - the fact. Designing for a hybrid model from the outset would likely yield a - simpler result + were added after the fact. Designing for a hybrid model from the outset + would likely yield a simpler result. * Unique ownership does support some usage patterns that arenas cannot directly accommodate. For example, you can reparent a message and the child will precisely follow the lifetime of its new parent. An arena would require you to either @@ -107,14 +106,15 @@ message with one that may be on a different arena. is far more accessible than it was in 2014 (when C++ introduced a thread-safe arena). We now have more tools at our disposal to ensure that we do not trigger data races in a thread-compatible arena like upb. -* A thread-compatible arena has a far simpler implementation. The C++ thread-safe +* Thread-compatible arenas are more performant. +* Thread-compatible arenas have a far simpler implementation. The C++ thread-safe arena relies on thread-local variables, which introduce complications on some platforms. It also requires far more subtle reasoning for correctness and - performance, and likely cannot match the performance of a thread-compatible arena. + performance. **fuse vs. no fuse** -* The `upb_Arena_Fuse()` operation is a key part of how we can support reparenting - of messages when the parent may be on a different arena. Without this, we have +* The `upb_Arena_Fuse()` operation is a key part of how upb supports reparenting + of messages when the parent may be on a different arena. Without this, upb has no way of supporting `foo.bar = bar` in dynamic languages without performing a deep copy. * A downside of `upb_Arena_Fuse()` is that passing an arena to a function can allow @@ -181,6 +181,11 @@ down by generated code vs core library in the future). | C++ (code size) | 904Ki | 6.1Ki | 1.88Ki | | C++ (full) | 983Ki | 6.1Ki | 1.88Ki | +"C++ (code size)" refers to protos compiled with `optimize_for = CODE_SIZE`, a mode +in which generated code contains reflection only, in an attempt to make the +generated code size smaller (however it requires the full runtime instead +of the lite runtime). + ## Bifurcated vs. Optional Reflection upb and C++ protos both offer reflection without making it mandatory. However