So to recap your question, you want:
- A non-optional type that is allocated by value/on the stack: You are happy directly using the object type for this.
- An optional type that is allocated by value/on the stack: You are happy using
boost::optional
for this (or you can use std::optional
from C++17).
- A non-optional type that is allocated on the heap and owns the pointed-to object.
- An optional type that is allocated on the heap and owns the pointed-to object.
You are unhappy that you can express the difference between 1 and 2, but both 3 and 4 usually use the same type (std::unique_ptr
). You suggest using std::unique_ptr
for 3, never allowing nullptr
, and some other thing for 4, but want to know what you can use. (In the comments you also accept the possibility of using std::unique_ptr
with nullptr
for 4 if something else can be found for 3.)
Literal answer to your question: you can simply use boost::optional<std::unique_ptr<T>>
for 4 (while using a bare unique_ptr
for 3 as you suggested).
Alternative literal answer to your question: As @StoryTeller said, you could define your own smart pointer type that is like unique_ptr
but disallows nullptr
, and use that for 3. A quicker (but very dirty) alternative is to force functions to return a pair
of both a unique_ptr
and a reference to that same object. Then only access the result through the reference, but only do so while the unique_ptr
still exists:
template<class T>
using RefAndPtr = std::pair<T&, std::unique_ptr<T>>;
RefAndPtr<Foo> getFoo()
{
std::unique_ptr<Foo> result = std::make_unique<Foo>();
return RefAndPtr<Foo>(*result, std::move(result));
}
My actual suggestion: Just suck it up and use std::unique_ptr
for both 3 and 4. Clarifying your intentions in the type system is a good thing, but too much of a good thing can be bad. Using either of the above options is just going to confuse the hell out of anyone that reads your code. And even if you stop people from incorrectly passing around nullptr
, what's to stop them passing a pointer around to the wrong object, or already-freed memory, etc.? At some point you have to specify things outside of the type system.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…