This is a percolation of ideas which originated this SO question:
Compound pointer traits class with method generalizing make_shared and make_unique?
The std::pointer_traits
class offers the following traits, basically:
Types: pointer
, element_type
, difference_type
, and rebind
(given a pointer-like type for pointing to T
, get a pointer-like type for pointing to U
)
Static methods:
to_address
- get the plain vanilla T* from some fancy pointer-to-T-like class, if possiblepointer_to
- opposite ofto_address
. This is a fishy method, since it's not clear what it means with respect to resource ownership.
I think it's useful to add at least two methods - for creating a pointer to a new object / array of objects, a-la std::make_shared
and std::make_unique
, and one for releasing ownership + getting the raw address. Here's my implementation:
#pragma once
#ifndef EXTRA_POINTER_TRAITS_HPP_
#define EXTRA_POINTER_TRAITS_HPP_
#include <memory>
template <typename Ptr>
struct extra_pointer_traits;
template <typename T>
struct extra_pointer_traits<T*>
{
using ptr_type = T*;
using element_type = T;
static ptr_type make(size_t count) { return new T[count]; }
static ptr_type make() { return new T; }
};
template <typename T>
struct extra_pointer_traits<T[]>
{
using ptr_type = T[];
using element_type = T;
static T* make(size_t count) { return new T[count]; }
static T* make() { return new T; }
};
template <typename T, class Deleter>
struct extra_pointer_traits<std::unique_ptr<T[], Deleter>>
{
using ptr_type = std::unique_ptr<T[], Deleter>;
using element_type = T;
static T* release(ptr_type& ptr) { return ptr.release(); }
static std::unique_ptr<T[], Deleter> make(size_t count)
{
return std::make_unique<T[]>(count);
}
};
template <typename T, class Deleter>
struct extra_pointer_traits<std::unique_ptr<T, Deleter>>
{
using ptr_type = std::unique_ptr<T, Deleter>;
using element_type = T;
static T* release(ptr_type& ptr) { return ptr.release(); }
static std::unique_ptr<T, Deleter> make()
{
return std::make_unique<T>();
}
};
template <typename T>
struct extra_pointer_traits<std::shared_ptr<T>>
{
using ptr_type = std::shared_ptr<T>;
using element_type = typename std::pointer_traits<ptr_type>::element_type;
// No release()
static std::shared_ptr<element_type[]> make(size_t count)
{
return std::make_shared<element_type[]>(count);
}
static std::shared_ptr<element_type> make()
{
return std::make_shared<element_type>();
}
};
#endif // EXTRA_POINTER_TRAITS_HPP_
I'm considering suggesting something like this as an addition to the existing traits class the standards committe, but for now I've implemented it as a separate class.
Note: To clarify - these are not all possible template specializations for pointer-like classes in the standard library, there would be a few more.