# Comparing new C++ and high-level C++ language bindings

## Quick reference

Here's how to recognize if a particular type/function/identifier in C++ code is
part of the new C++ bindings or high-level C++ bindings.

Taking the [`examples.keyvaluestore.baseline`](https://fuchsia.dev/docs/development/languages/fidl/examples/key_value_store) library as example:

    library examples.keyvaluestore.baseline;

    type Item = struct {
        key string:128;
        value vector<byte>:64000;
    };

    type WriteError = flexible enum {
        UNKNOWN = 0;
        INVALID_KEY = 1;
        INVALID_VALUE = 2;
        ALREADY_EXISTS = 3;
    };

    @discoverable
    open protocol Store {
        /// Writes an item to the store.
        flexible WriteItem(struct {
            attempt Item;
        }) -> () error WriteError;
    };

Here are how the various FIDL elements will map to in the C++ bindings. Note
that in the table "C++" refers to the new C++ bindings, and applies equally to
both natural domain objects and wire domain objects. "Natural" refers to the
natural domain objects in the new C++ bindings. "Wire" refers to the wire domain
objects in the new C++ bindings.

| FIDL element |   | C++ natural types | Comments |
|---|---|---|---|
| Header include | C++ | #include \<fidl/examples.keyvaluestore.baseline/cpp/fidl.h\> | Format is \`fidl/library name/cpp/fidl.h\` |
| Header include | HLCPP | #include \<examples/keyvaluestore/baseline/cpp/fidl.h\> | Format is \`slash separated library name/cpp/fidl.h\` |
| The library | C++ | ::examples_keyvaluestore_baseline | New C++ uses a single level namespace. HLCPP uses nested namespaces. |
| The library | HLCPP | ::examples::keyvaluestore::baseline | New C++ uses a single level namespace. HLCPP uses nested namespaces. |
| Item struct | Natural | ::examples_keyvaluestore_baseline::Item | On top of the namespace differences, the wire types are nested under "::wire". |
| Item struct | Wire | ::examples_keyvaluestore_baseline::wire::Item | On top of the namespace differences, the wire types are nested under "::wire". |
| Item struct | HLCPP | ::examples::keyvaluestore::baseline::Item | On top of the namespace differences, the wire types are nested under "::wire". |
| WriteError enum | Natural | ::examples_keyvaluestore_baseline::WriteError | On top of the namespace differences, the wire types are nested under "::wire". In case of enums and bits, the wire types and natural types are equivalent. There is just an extra type alias. |
| WriteError enum | Wire | ::examples_keyvaluestore_baseline::wire::WriteError | On top of the namespace differences, the wire types are nested under "::wire". In case of enums and bits, the wire types and natural types are equivalent. There is just an extra type alias. |
| WriteError enum | HLCPP | ::examples::keyvaluestore::baseline::WriteError | On top of the namespace differences, the wire types are nested under "::wire". In case of enums and bits, the wire types and natural types are equivalent. There is just an extra type alias. |
| string:128 | Natural | std::string |   |
| string:128 | Wire | fidl::StringView |   |
| string:128 | HLCPP | std::string |   |
| vector\<byte\>:64000 | Natural | std::vector\<uint8_t\> |   |
| vector\<byte\>:64000 | Wire | fidl::VectorView\<uint8_t\> |   |
| vector\<byte\>:64000 | HLCPP | std::vector\<uint8_t\> |   |
| protocol Store | C++ | ::examples_keyvaluestore_baseline::Store | A marker type that carries some information about the protocol |
| protocol Store | HLCPP | ::examples::keyvaluestore::baseline::Store | An abstract base class that contains methods in the protocol |
| client_end:Store | C++ | fidl::ClientEnd\<Store\> |   |
| client_end:Store | HLCPP | fidl::InterfaceHandle\<Store\> |   |
| server_end:Store | C++ | fidl::ServerEnd\<Store\> |   |
| server_end:Store | HLCPP | fidl::InterfaceRequest\<Store\> |   |
| Client and server types for the Store protocol | Natural | Client: fidl::Client\<Store\> Synchronous client: fidl::SyncClient\<Store\> Server interface: fidl::Server\<Store\> Event handler interface: fidl::EventHandler\<Store\> ||
| Client and server types for the Store protocol | Wire | Client: fidl::WireClient\<Store\> Synchronous client: fidl::WireSyncClient\<Store\> Server interface: fidl::WireServer\<Store\> Event handler interface: fidl::WireEventHandler\<Store\> ||
| Client and server types for the Store protocol | HLCPP | Client: fidl::InterfacePtr\<Store\> Synchronous client: fidl::SynchronousInterfacePtr\<Store\> Server interface: Store Event handler interface: N/A. InterfacePtr has setters that take one callback per event declaration. ||

Here's the most common way to set up a client:

### C++ (Natural)

```c++
  // Connect to the protocol inside the component's namespace. This can fail so it's wrapped in a
  // |zx::result| and it must be checked for errors.
  zx::result client_end = component::Connect<examples_canvas_baseline::Instance>();
  if (!client_end.is_ok()) {
    FX_LOGS(ERROR) << "Synchronous error when connecting to the |Instance| protocol: "
                   << client_end.status_string();
    return -1;
  }

  // Create an instance of the event handler.
  EventHandler event_handler(loop);

  // Create an asynchronous client using the newly-established connection.
  fidl::Client client(std::move(*client_end), dispatcher, &event_handler);
  FX_LOGS(INFO) << "Outgoing connection enabled";
```

### C++ (Wire)

```c++
  // Connect to the protocol inside the component's namespace. This can fail so it's wrapped in a
  // |zx::result| and it must be checked for errors.
  zx::result client_end = component::Connect<examples_canvas_baseline::Instance>();
  if (!client_end.is_ok()) {
    FX_LOGS(ERROR) << "Synchronous error when connecting to the |Instance| protocol: "
                   << client_end.status_string();
    return -1;
  }

  // Create an instance of the event handler.
  EventHandler event_handler(loop);

  // Create an asynchronous client using the newly-established connection.
  fidl::WireClient client(std::move(*client_end), dispatcher, &event_handler);
  FX_LOGS(INFO) << "Outgoing connection enabled";
```

See the [canvas](https://fuchsia.dev/docs/development/languages/fidl/examples/canvas) example for the full code listing and explanation.

Here's the most common way to implement a server:

### C++ (Natural)

```c++
// An implementation of the |Instance| protocol.
class InstanceImpl final : public fidl::Server<examples_canvas_baseline::Instance> {
  void AddLine(AddLineRequest& request, AddLineCompleter::Sync& completer) override {
    // ...
  }
};
```

### C++ (Wire)

```c++
// An implementation of the |Instance| protocol.
class InstanceImpl final : public fidl::WireServer<examples_canvas_baseline::Instance> {
  void AddLine(AddLineRequestView request, AddLineCompleter::Sync& completer) override {
    // ...
  }
};
```

See the [canvas](https://fuchsia.dev/docs/development/languages/fidl/examples/canvas) example for the full code listing and explanation.

## New C++ bindings

The new C++ bindings supports both low-level and high-level use cases, by
offering two families of generated domain objects, and corresponding client and
server APIs that speak those types.

> [!NOTE]
> **Note:** prefer natural types unless optimizing for critical performance and memory allocation. Refer to the [C++ tutorials](https://fuchsia.dev/docs/development/languages/fidl/tutorials/cpp/README#natural_and_wire_domain_objects).

### Natural types

- Optimized to meet the needs of high-level service programming.
- Represent data structures using idiomatic C++ types such as `std::vector`, `std::optional`, and `std::string`.
- Use smart pointers to manage heap allocated objects.
- Use `zx::handle` to manage handle ownership.
- Can convert data between their wire (e.g. `fidl::StringView`) and natural type representations (e.g. `std::string`).

### Wire types

- Optimized to meet the needs of low-level systems programming while providing slightly more safety and features than the C bindings.
- Represent data structures whose memory layout coincides with the wire format, i.e. satisfying C++ Standard Layout. This opens the door to in-place encoding and decoding.
- Generated structures are views of an underlying buffer; they do not own memory.
- Support in-place access of FIDL messages.
- Provide fine-grained control over memory allocation.
- Use owned handle types such as `zx::handle`. Note that since generated structures are views of an underlying buffer, a parent structure will only own child handles if it also owns their underlying buffer. For example, a FIDL struct owns all the handles stored inline, but a FIDL vector of structs containing handles will be represented as a vector view, which will not own the out-of-line handles.

### Client and server APIs

- Code generator produces more code compared to the C bindings. This includes constructors, destructors, copy/move functions, conversions between domain object families, protocol client implementations, and pure virtual server interfaces.
- Users implement a server by sub-classing a provided server interface and overriding the pure virtual methods for each operation.
- Clients supporting sync and async calls, and sync and async event handling.
- Requires C++17 or above.

Refer to the [New C++ tutorial](https://fuchsia.dev/docs/development/languages/fidl/tutorials/cpp) to get started.

## High-level C++ bindings

> [!NOTE]
> **Note:** If you are developing within the **fuchsia.git** tree, you are recommended to use the [new C++ bindings](https://fuchsia.dev/docs/development/languages/fidl/tutorials/cpp/README) bindings, which offer better ergonomics, thread-safety, and performance.

- Optimized to meet the needs of high-level service programming.
- Represent data structures using idiomatic C++ types such as `std::vector`, `std::optional`, and `std::string`.
- Use smart pointers to manage heap allocated objects.
- Use `zx::handle` (libzx) to manage handle ownership.
- Can convert data from in-place FIDL buffers to idiomatic heap allocated objects.
- Can convert data from idiomatic heap allocated objects (e.g. `std::string`) to in-place buffers (e.g. as a `fidl::StringView`).
- Code generator produces more code compared to the C bindings. This includes constructors, destructors, protocol proxies, protocol stubs, copy/move functions, and conversions to/from in-place buffers.
- Client performs protocol dispatch by sub-classing a provided stub and implementing the virtual methods for each operation.
- Both async and synchronous clients are supported. However, the async clients are not thread-safe.
- Requires C++14 or above.

## Summary

| Category | New C++ with wire types | New C++ with natural types | High-level C++ |
|---|---|---|---|
| **audience** | drivers and performance-critical applications | high-level services | high-level services |
| **abstraction overhead** | RAII closing of handles ^[1](https://fuchsia.dev/fuchsia-src/development/languages/fidl/guides/c-family-comparison#fn1)^ | heap allocation, construction, destruction | heap allocation, construction, destruction |
| **type safe types** | enums, structs, unions, handles, protocols | enums, structs, unions, handles, protocols | enums, structs, unions, handles, protocols |
| **storage** | stack, user-provided buffer, or heap | heap | heap |
| **lifecycle** | manual or automatic free | automatic free (RAII) | automatic free (RAII) |
| **receive behavior** | decode in-place | decode into heap | decode then move to heap |
| **send behavior** | copy or vectorize | copy | copy |
| **calling protocol methods** | free functions or proxy | free functions or proxy | call through proxies, register callbacks |
| **implementing protocol methods** | manual dispatch or implement stub interface | implement stub interface | implement stub object, invoke callbacks |
| **async client** | yes | yes | yes |
| **async server** | yes (unbounded) ^[2](https://fuchsia.dev/fuchsia-src/development/languages/fidl/guides/c-family-comparison#fn2)^ | yes (unbounded) \[\^2\] | yes (unbounded) |
| **parallel server dispatch** | yes ^[3](https://fuchsia.dev/fuchsia-src/development/languages/fidl/guides/c-family-comparison#fn3)^ | yes \[\^3\] | no |
| **generated code footprint** | large | large | large |

[](https://issues.fuchsia.dev/issues/new?component=1439230&template=1881640&description=Issue+on:+https://fuchsia.dev/docs/development/languages/fidl/guides/c-family-comparison.md "Report a bug or suggest improvements on this page") [](https://cs.opensource.google/fuchsia/fuchsia/+/main:docs/development/languages/fidl/guides/c-family-comparison.md "View the source code of this page") [](https://ci.android.com/edit?repo=fuchsia/fuchsia/main&file=docs/development/languages/fidl/guides/c-family-comparison.md&cloneRepo=fuchsia/fuchsia:refs/heads/main&fullPath=fuchsia/docs/development/languages/fidl/guides/c-family-comparison.md "Edit the source code of this page")

*** ** * ** ***

1. Generated types own all handles stored inline. Out-of-line handles
   e.g. those behind a pointer indirection are not closed when the containing
   object of the pointer goes away. In those cases, the bindings provide a
   `fidl::DecodedValue` object to manage all handles associated with a call. [↩](https://fuchsia.dev/fuchsia-src/development/languages/fidl/guides/c-family-comparison#fnref1)

2. The bindings library defined in [lib/fidl](https://cs.opensource.google/fuchsia/fuchsia/+/main:/sdk/lib/fidl/cpp/wire) can
   dispatch an unbounded number of in-flight transactions via `fidl::BindServer`
   defined in
   [lib/fidl/cpp/wire/channel.h](https://cs.opensource.google/fuchsia/fuchsia/+/main:/sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/channel.h). [↩](https://fuchsia.dev/fuchsia-src/development/languages/fidl/guides/c-family-comparison#fnref2)

3. The bindings library [lib/fidl](https://cs.opensource.google/fuchsia/fuchsia/+/main:/sdk/lib/fidl/cpp/wire) enables parallel
   dispatch using the `EnableNextDispatch()` API defined in
   [lib/fidl/cpp/wire/async_transaction.h](https://cs.opensource.google/fuchsia/fuchsia/+/main:/sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/async_transaction.h). [↩](https://fuchsia.dev/fuchsia-src/development/languages/fidl/guides/c-family-comparison#fnref3)