Document Number: P0653r0
Date: 2017-05-28
Project: Programming Language C++
Audience: Library Evolution Working Group
Author: Glen Joseph Fernandes
(glenjofe@gmail.com)
pointer_traits (called to_address) to obtain a raw
pointer from an object of any pointer-like type.
It is often necessary to obtain a raw pointer from an object of any
pointer-like type. One common use is writing allocator-aware code where an
allocator's pointer member type is not a raw pointer type.
Typically the expression addressof(*p) is used but this is not
well-defined when p does not reference storage that has an object
constructed in it. This means that using this expression to obtain a raw
pointer for the purpose of constructing an object (e.g. via a placement
new-expression or via an allocator) is incorrect.
A typical example of such code:
P p = a.allocate(n); new (addressof(*p)) T();
The correct code now looks like:
P p = a.allocate(n); new (pointer_traits<P>::to_address(p)) T();
Typically implementors work around this problem by defining a utility like the following:
template <class Ptr>
typename pointer_traits<Ptr>::element_type* to_address(Ptr p) noexcept
{
return to_address(p.operator->());
}
template <class T>
T* to_address(T* p) noexcept
{
return p;
}
The C++ standard library already provides pointer_traits
for supporting any pointer-like types and this to_address is
the natural inverse of its pointer_to member function.
The Boost C++ library collection now
contains an implementation of this proposal in the Core library. That
boost::pointer_traits implementation is used by several Boost
libraries, starting with the 1.65 release.
All changes are relative to N4640.
1. Insert into 20.10.3 [pointer.traits] as follows:
namespace std {
template <class Ptr> struct pointer_traits {
using pointer = Ptr;
using element_type = see below;
using difference_type = see below;
template <class U> using rebind = see below;
static pointer pointer_to(see below r);
static element_type* to_address(pointer p) noexcept;
};
template <class T> struct pointer_traits<T*> {
using pointer = T*;
using element_type = T;
using difference_type = std::ptrdiff_t;
template <class U> using rebind = U*;
static pointer pointer_to(see below r) noexcept;
static element_type* to_address(pointer p) noexcept;
};
}
2. Add to 20.10.3.1 [pointer.traits.functions] as follows:
static element_type* pointer_traits::to_address(pointer p) noexcept;
static element_type* pointer_traits<T*>::to_address(pointer p) noexcept;Returns: A pointer of type
element_type*that references the same location as the argumentp.Remarks: The first member function returns
pointer_traits<E>::to_address(expr)where expr isp.operator->()and E is its type. The second member function returnsp.
Peter Dimov suggested a better design as well as reviewed the implementation and tests of the Boost version. Jonathan Wakely pointed out the issue that motivated this proposal. Michael Spencer reviewed this paper.