laptou
laptou

Reputation: 6981

How do I call a C++ constructor using the cxx crate?

I found this question, but it is 3 years old and since then, crates like cxx have come into existence. Is it possible now to construct a C++ object from Rust, or do I still have to create a shim?

Upvotes: 3

Views: 1470

Answers (1)

dtolnay
dtolnay

Reputation: 10992

To the extent that constructors "return" a C++ type by value, they're not translatable to Rust because Rust moves (memcpy) are incompatible with C++ moves (which can require a move constructor to be called). Translating an arbitrary constructor to fn new() -> Self would not be correct.

You can bind them unsafely with bindgen which assumes moving without a constructor call is okay, or you can use the "shared struct" approach in the readme which is safely movable in either language, or you can include! a shim which does the construction behind a unique_ptr or similar.

That last approach would look something like:

// suppose we have a struct with constructor `ZeusClient(std::string)`

// in a C++ header:
std::unique_ptr<ZeusClient> zeus_client_new(rust::Str arg);

// in the corresponding C++ source file:
std::unique_ptr<ZeusClient> zeus_client_new(rust::Str arg) {
  return make_unique<ZeusClient>(std::string(arg));
}

// in the Rust cxx bridge:
extern "C++" {
    include!("path/to/zeus/client.h");
    include!("path/to/constructorshim.h");

    type ZeusClient;

    fn zeus_client_new(arg: &str) -> UniquePtr<ZeusClient>;
}

In the future it's very likely CXX will include something builtin for this pattern, or maybe for the special case of structs without a move constructor. This is tracked in dtolnay/cxx#280.

extern "C++" {
    type ZeusClient;

    fn new(arg: &str) -> ZeusClient;  // will verify there is no move constructor

    fn new(arg: &str) -> UniquePtr<ZeusClient>;  // okay even with move constructor
}

Upvotes: 6

Related Questions