std::unique_ptr
是可空的。每当被移动或默认构造时,它就会变为null。
std::unique_ptr
是您的可空堆分配对象。
可以编写不可空的value_ptr
。请注意,在移动时有额外的成本:
template<class T>
class value_ptr {
struct ctor_key_token{ explicit ctor_key_token(int){} };
public:
template<class A0, class...Args, class dA0 = std::decay_t<A0>,
std::enable_if_t<!std::is_same<dA0, ctor_key_token>{} && !std::is_same<dA0, value_ptr>{}, int> = 0
>
value_ptr( A0&& a0, Args&&... args):
value_ptr( ctor_key_token(0), std::forward<A0>(a0), std::forward<Args>(args)... )
{}
value_ptr(): value_ptr( ctor_key_token(0) ) {}
template<class X, class...Args>
value_ptr( std::initializer_list<X> il, Args&&... args ):
value_ptr( ctor_key_token(0), il, std::forward<Args>(args)... )
{}
value_ptr( value_ptr const& o ):
value_ptr( ctor_key_token(0), *o.state )
{}
value_ptr( value_ptr&& o ):
value_ptr( ctor_key_token(0), std::move(*o.state) )
{}
value_ptr& operator=(value_ptr const& o) {
*state = *o.state;
return *this;
}
value_ptr& operator=(value_ptr && o) {
*state = std::move(*o.state);
return *this;
}
T* get() const { return state.get(); }
T* operator->() const { return get(); }
T& operator*() const { return *state; }
template<class U,
std::enable_if_t<std::is_convertible<T const&, U>{}, int> =0
>
operator value_ptr<U>() const& {
return {*state};
}
template<class U,
std::enable_if_t<std::is_convertible<T&&, U>{}, int> =0
>
operator value_ptr<U>() && {
return {std::move(*state)};
}
private:
template<class...Args>
value_ptr( ctor_key_token, Args&&... args):
state( std::make_unique<T>(std::forward<Args>(args)...) )
{}
std::unique_ptr<T> state;
};
这是一个非空堆分配值语义对象的草图。
注意,当你从中移动时,它不会释放旧内存。唯一不拥有堆上的
T
的时候是在构造期间(只能通过抛出异常终止)和销毁期间(因为
state
被销毁)。
更高级的版本可以有自定义销毁器、克隆器和移动器,允许存储多态值语义类型或不可复制类型。
将几乎永远不为空或很少为空的类型用作永不为空会导致错误。所以不要这样做。
示例:
在线示例。
unique_ptr
是可空的,你不能将其视为非空。 - n. m.template <typename T> using nullable_unique_ptr = unique_ptr<T>;
这种类型是按照惯例可空的。 - n. m.