3 ms·
It seems like the obvious answer is to have a nullable_hazard_ptr and a hazard_ptr, which composites nullable_hazard_ptr. nullable_hazard_ptr is movable and def
by fluoridation 3y ago
It seems like the obvious answer is to have a nullable_hazard_ptr and a hazard_ptr, which composites nullable_hazard_ptr. nullable_hazard_ptr is movable and default-constructible, while hazard_ptr can only be constructed with arguments and cannot be moved, but can be constructed from a nullable_hazard_ptr &&.
So if you need to return a hazard pointer from a function you return a nullable_hazard_ptr and the caller can choose to assigned that value to auto or to hazard_ptr. In the latter case, the caller will have the guarantee that the object is valid because if the function returned a null pointer the constructor will have thrown an exception. Furthermore the pointer will remain valid until it goes out of scope because there's nothing that can be done to it to make it invalid (UB notwithstanding). Of course, anyone who chooses to use nullable_hazard_ptr will need to check for validity.
Unfortunately this does mean that it's the responsibility of the callers to choose the right pointer.
>In the constructor of a class with a hazard pointer member I needed to be able to initialize a hazard pointer on the stack and then move it into the member variable. (Because the hazard pointer constructor is fallible, I needed to catch exceptions thrown from the hazard pointer's constructor and retry from within the containing class's constructor, so I couldn't just use an initializer list.)
This particular case would be handled by calling a helper function in the constructor's initialization list for each hazard_ptr member. As I said, this function should return nullable_hazard_ptr (always non-null; you will have already ensured this inside the function. You still need the nullable type because it's the only one that can be moved).
Ultimately what you have is something analogous to std::lock_guard and std::unique_lock. You are acquiring and releasing a resource and in some cases you need to tie the acquisition into the program structure and in other cases you need to be able untie it. There's no way to specify that in C++'s type system other than by having two separate types.
- senderista 3y agoThanks for this instructive example.