Closed oremanj closed 4 months ago
These harsh C-style casts exist so that everything works with forward declarations. I am extensively using ref<>
in a codebase where I want to be able to write:
/// Forward declaration
class A;
struct B {
ref<A> a;
};
which is something that one can do with raw pointers. To turn those into reference-counted pointers, we can't assume to actually know anything about the type, or the full definition of A
would need to be included, which contributes to header bloat.
All right, I'll leave well enough alone then :-) Since there's nowhere that's required to have a complete T
(even the delete
can indirect through the virtual dtor in the base class), there's nowhere that one could validate the base relationship.
If you manage to form a
nb::ref<T>
where T does not inherit fromnb::intrusive_base
, thennb::ref
will reinterpret the first two words of aT
object as if they were anintrusive_base
, due to the widespread use of C-style pointer casts in the implementation ofnb::ref
. This seems like an unnecessary hazard to me.I'm not entirely sure what the purpose of the casts is. This PR assumes that the C-style cast is used to access an
intrusive_base
subobject even if it is inherited privately; it keeps the cast ifstd::is_base_of<intrusive_base, T>
is true, and eschews it otherwise (in which case the user had better have provided their owninc_ref
anddec_ref
ADL functions). Alternatively, if the intention was thatnb::ref<T>
only works if T inheritsnb::intrusive_base
, we could add a static assert to that effect instead.