From: Glen Fernandes (glen.fernandes_at_[hidden])
Date: 2020-01-29 14:18:21


Gavin, in case my explanation in that earlier reply wasn't clear:

Given std::unique_ptr<Foo, D> p;

1. Users know that *p and p->x do the right thing by Foo.
2. p.get() will get them a D::pointer.

This D::pointer might be Foo*, or it might be offset_ptr<Foo> or it
might be alloc_ptr<offset_ptr<Foo>> or any other pointer-like type.

To get a Foo* out of p.get() regardless of which of the above three it
returns, you can call:

    Foo* q = std::to_address(p.get()); // C++20 in std, C++03 in boost

Or, if you know that p is not a null pointer, you can also use:

    if (p) {
        Foo* q = std::addressof(*p); // C++11 in std, C++03 in boost
    }

std::unique_ptr<T, D> was always designed for this (since C++11).

Because not all pointers we use are raw pointers. An
Allocator::pointer might not be X*, it might be offset_ptr<X>, or it
might be aligned_ptr<offset_ptr<X>>.

This property of unique_ptr is also unrelated to allocate_unique
(which just leverages this with a fancy-pointer around the
Allocator::pointer which in turn might be a fancy-pointer).

But even today, users are using unique_ptr with non-raw pointers (like
Allocators where Allocator::pointer is offset_ptr<X> instead of X*).
They don't assume that p.get() returns a raw X* pointer.

This might be a lesser known property of unique_ptr to some
(especially those that do not work much with custom allocators), but
this is the way it has always been and intentionally so.

Glen