-
Notifications
You must be signed in to change notification settings - Fork 110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Should not_null<>
be two different classes?
#298
Comments
I realized that, for raw pointers, moving just copies, hence there is no dedicated moved-from state to worry about. In fact, the postcondition checks in That further reduces the necessity for a type with R.30: Take smart pointers as parameters only to explicitly express lifetime semantics The So perhaps there isn't much use for |
4e0b7d2 addresses this point and adds a specialization of |
Furthermore, if we ever wanted a // std::size_t compute_hash(std::unique_ptr<Resource> const& res);
std::size_t compute_hash(gsl::not_null<std::unique_ptr<Resource> const&> res);
// "will" or "might" reseat pointer
// void reseat(unique_ptr<widget>&);
void reseat(gsl::not_null<unique_ptr<widget>&>);
// "might" retain refcount
// void may_share(shared_ptr<widget> const&);
void may_share(gsl::not_null<shared_ptr<widget> const&>); But for now, let's not. Either way, there is really no need for a dedicated type with |
While reviewing #297 it occurred to me that there are two possible interpretations of the
not_null<>
type mentioned by the C++ Core Guidelines:not_null_1<>
, a building-block type, to be used e.g. as data member or as container element:not_null_1<>
is copyable if the pointer type is copyable. It is also movable; the move leaves behind a "valid but unspecified" pointer object:Because C++ doesn't have destructive move, we have to worried about the moved-from state. Although its occurrence cannot be statically prevented¹,
not_null_1<>
makes sure that the moved-from state doesn't proliferate (⇒ it checks fornullptr
in all constructors), and that pointers in moved-from state are not accessed (⇒ it checks fornullptr
in accessor functions such asget()
,as_nullable()
,operator ->()
).not_null_2<>
, a type with reference/borrow semantics used in function signatures to express a function precondition (that the argument shall not benullptr
) through the type system:not_null_2<P>
is effectivelyP const&
; it is copyable, but that just copies the reference to the pointer. (Copy assignment could also be supported by actually storingP const*
, notP const&
.)not_null_2<>
hence does not need to be movable. It establishes its invariant (pointer is notnullptr
) in the explicitnot_null_2<P>::not_null_2(P const&)
constructor. Not being movable, it has no moved-from state, and hence no further checks are necessary in copy constructors/assignment operators or accessor methods.Using
not_null_2<P>
instead ofnot_null_1<P> const&
in function signatures is advantageous because it means the onus of checking the precondition is on the caller:In this case,
compute_hash_2()
could even benoexcept
even ifgsl_CONFIG_CONTRACT_VIOLATION_THROWS
is defined because the precondition check is run by the caller before the function is invoked.The examples in the Core Guidelines are too shallow to shed light on which of these semantics was actually intended. gsl-lite currently implements
gsl::not_null<>
withnot_null_1<>
semantics. However, I think thatnot_null_2<>
actually resembles more closely what the Guidelines authors had in mind; they likennot_null<>
tospan<>
and seem to imply it has borrow semantics, and all their examples would work fine withnot_null_2<>
.I'm pondering whether we want something like
not_null_2<>
in the library, perhaps namedgsl::not_null_arg<>
,gsl::not_null_ref<>
, orgsl::not_null_view<>
. Comments welcome.¹: Some static analyzers can diagnose obvious cases of use-after-move, e.g. Clang-Tidy.
The text was updated successfully, but these errors were encountered: