- Can
std::unique_ptr
manage pointers only, or fancy pointers (pointer-like types) too?
I assume "fancy pointers too", because for resources like files/sockets, fancy pointers can be a great tool. And there seems no reason std::unique_ptr
shouldn't support them.
- Why are there inconsistent ways to test empty-ness of the managed pointer?
There are different ways to test empty-ness of the managed pointer in std::unique_ptr
(GCC):
- In
~unique_ptr()
:if (__ptr != nullptr)
(code) - In
reset()
:if (__old_p)
(code) - In
operator bool()
:return get() == pointer() ? false : true;
(code)
The problem is that they have different requirements to the pointer type:
bool operator ==(pointer, nullptr_t)
operator bool()
bool operator ==(pointer, pointer)
The inconsistent usage means all of them are needed, while one of them would suffice semantically.
#include <memory>using namespace std;class File { FILE * pf_ = nullptr;public: File() = default; File(const char * pathname) { /*...*/ }; void Close() { /*...*/ }; // All are needed to make std::unique_ptr work explicit operator bool() const { return pf_ == nullptr; } bool operator ==(nullptr_t) const { return pf_ == nullptr; } bool operator ==(File) const { /*...*/ return true; };};struct FileCloser { using pointer = File; void operator ()(File p) const { p.Close(); }};int main() { using FilePtr = unique_ptr<File, FileCloser>; FilePtr p(File("./abc")); if(p) p.reset();}
https://godbolt.org/z/fjPjWzzhW
IMHO, std::unique_ptr
should require minimum from the pointer type. One solution is to add a static member, e.g. __test_p
, and use it to test empty-ness consistently:
template<typename T, typename D = std::default_delete<T>>class unique_ptr{// ...private: static constexpr bool __test_p(pointer p) noexcept { if constexpr (is_convertible_v<pointer, bool>) return bool(p); else if constexpr (requires {{ p != nullptr} -> convertible_to<bool>; }) return p != nullptr; else return p != pointer(); }// ...};