pub struct CppRef<T: ?Sized>(/* private fields */);Expand description
A C++ const reference. These are different from Rust’s &T in that
these may exist even while the object is mutated elsewhere. See also
CppMutRef for the mutable equivalent.
The key rule is: we never dereference these in Rust. Therefore, any UB here cannot manifest within Rust, but only across in C++, and therefore they are equivalently safe to using C++ references in pure-C++ codebases.
Important: you might be wondering why you’ve never encountered this type.
These exist in autocxx-generated bindings only if the unsafe_references_wrapped
safety policy is given. This may become the default in future.
§Usage
These types of references are pretty useless in Rust. You can’t do
field access. But, you can pass them back into C++! And specifically,
you can call methods on them (i.e. use this type as a this). So
the common case here is when C++ gives you a reference to some type,
then you want to call methods on that reference.
§Calling methods
As noted, one of the main reasons for this type is to call methods.
Currently, that depends on unstable Rust features. If you can’t
call methods on one of these references, check you’re using nightly
and add #![feature(arbitrary_self_types)] to your crate.
§Lifetimes
A CppRef is not associated with any Rust lifetime. Normally, for
ergonomics, you actually may want a lifetime associated.
CppLtRef gives you this.
§Field access
Field access would be achieved by adding C++ get and/or set methods.
It’s possible that a future version of autocxx could generate such
getters and setters automatically, but they would need to be unsafe
because there is no guarantee that the referent of a CppRef is actually
what it’s supposed to be, or alive. CppRefs may flow from C++ to Rust
via arbitrary means, and with sufficient uses of get and set it would
even be possible to create a use-after-free in pure Rust code (for instance,
store a CppPin in a struct field, get a CppRef to its referent, then
use a setter to reset that field of the struct.)
§Nullness
Creation of a null C++ reference is undefined behavior (because such
a reference can only be created by dereferencing a null pointer.)
However, in practice, they exist, and we need to be compatible with
pre-existing C++ APIs even if they do naughty things like this.
Therefore this CppRef type does allow null values. This is a bit
unfortunate because it means Option<CppRef<T>>
occupies more space than CppRef<T>.
§Dynamic dispatch
You might wonder if you can do this:
let CppRef<dyn Trait> = ...; // obtain some CppRef<concrete type>Dynamic dispatch works so long as you’re using nightly (we require another
unstable feature, dispatch_from_dyn). But we need somewhere to store
the trait object, and CppRef isn’t it – a CppRef can only store a
simple pointer to something else. So, you need to store the trait object
in a Box or similar:
trait SomeTrait {
fn some_method(self: CppRef<Self>)
}
impl SomeTrait for ffi::Concrete {
fn some_method(self: CppRef<Self>) {}
}
let obj: Pin<Box<dyn SomeTrait>> = ffi::Concrete::new().within_box();
let obj = CppPin::from_pinned_box(obj);
farm_area.as_cpp_ref().some_method();§Implementation notes
Internally, this is represented as a raw pointer in Rust. See the note above
about Nullness for why we don’t use core::ptr::NonNull.
Implementations§
Source§impl<T: ?Sized> CppRef<T>
impl<T: ?Sized> CppRef<T>
Sourcepub unsafe fn as_ref(&self) -> &T
pub unsafe fn as_ref(&self) -> &T
Get a regular Rust reference out of this C++ reference.
§Safety
Callers must guarantee that the referent is not modified by any other C++ or Rust code while the returned reference exists. Callers must also guarantee that no mutable Rust reference is created to the referent while the returned reference exists.
Callers must also be sure that the C++ reference is properly aligned, not null, pointing to valid data, etc.
Sourcepub fn const_cast(&self) -> CppMutRef<T>
pub fn const_cast(&self) -> CppMutRef<T>
Create a mutable version of this reference, roughly equivalent
to C++ const_cast.
The opposite is to use AsCppRef::as_cpp_ref on a CppMutRef
to obtain a CppRef.
§Safety
Because we never dereference a CppRef in Rust, this cannot create
undefined behavior within Rust and is therefore not unsafe. It is
however generally unwise, just as it is in C++. Use sparingly.