Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is there no std::allocate_unique function in C++14?

Tags:

Why does shared_ptr have allocate_shared while unique_ptr does not have allocate_unique?
I would like to make a unique_ptr using my own allocator: do I have to allocate the buffer myself and then assign it to a unique_ptr?
This seems like an obvious idiom.

like image 260
hatcat Avatar asked Apr 17 '14 10:04

hatcat


People also ask

How do you create a unique pointer in C++?

auto ptr = make_unique<int>(); // Create a new unique_ptr object. auto ptr = make_unique<int>(); The dynamically allocated object is destroyed when the created unique pointer object is destroyed.

What does make_unique return C++?

template<class U> unique_ptr<U> make_unique(U&& value); Returns: A unique_ptr to an object of type U , initialized to move(value) .

What is a unique pointer in C++?

(since C++11) std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope. The object is disposed of, using the associated deleter when either of the following happens: the managing unique_ptr object is destroyed.

When was make_unique introduced?

The std::make_unique function was introduced in the C++14 standard. Make sure to compile with the -std=c++14 flag to be able to use this function. The object gets destroyed once p goes out of scope.


2 Answers

do I have to allocate the buffer myself and then assign it to a unique_ptr?

Not just a buffer, a pointer to an object. But the object might need to be destroyed by the allocator, and the memory definitely needs to deallocated by the allocator, so you also need to pass the allocator the the unique_ptr. It doesn't know how to use an allocator, so you need to wrap it in a custom deleter, and that becomes part of the unique_ptr's type.

I think a generic solution would look something like this:

#include <memory>  template<typename Alloc> struct alloc_deleter {   alloc_deleter(const Alloc& a) : a(a) { }    typedef typename std::allocator_traits<Alloc>::pointer pointer;    void operator()(pointer p) const   {     Alloc aa(a);     std::allocator_traits<Alloc>::destroy(aa, std::addressof(*p));     std::allocator_traits<Alloc>::deallocate(aa, p, 1);   }  private:   Alloc a; };  template<typename T, typename Alloc, typename... Args> auto allocate_unique(const Alloc& alloc, Args&&... args) {   using AT = std::allocator_traits<Alloc>;   static_assert(std::is_same<typename AT::value_type, std::remove_cv_t<T>>{}(),                 "Allocator has the wrong value_type");    Alloc a(alloc);   auto p = AT::allocate(a, 1);   try {     AT::construct(a, std::addressof(*p), std::forward<Args>(args)...);     using D = alloc_deleter<Alloc>;     return std::unique_ptr<T, D>(p, D(a));   }   catch (...)   {     AT::deallocate(a, p, 1);     throw;   } }  int main() {   std::allocator<int> a;   auto p = allocate_unique<int>(a, 0);   return *p; } 
like image 136
Jonathan Wakely Avatar answered Sep 22 '22 13:09

Jonathan Wakely


Why does shared_ptr have allocate_shared while unique_ptr does not have allocate_unique?

shared_ptr needs it so that it can allocate its internal shared state (the reference count and deleter), as well as the shared object, using the allocator. unique_ptr only manages the object; so there is no need to provide an allocator to the unique_ptr itself, and less need for an allocate function.

(There is also less need for make_unique for the same reason, which is probably why it didn't feature in C++11, but was added to C++14 by popular demand for the sake of consistency. Maybe the same demand will add allocate_unique to a future standard.)

do I have to allocate the buffer myself and then assign it to a unique_ptr?

Yes. Or you could write your own allocate_unique; unlike allocate_shared, it's possible, and reasonably straightforward, to implement it separately from unique_ptr itself. (As mentioned in the comments, you'd have to make sure it used an appropriate deleter for the allocator; the default deleter would use delete and go horribly wrong).

This seems like an obvious idiom.

Indeed. But so are many other idioms, and not everything can (or should) be standardised.

For a more official justification of the current lack of allocate_unique, see the proposal for make_unique, specifically section 4 (Custom Deleters).

like image 44
Mike Seymour Avatar answered Sep 18 '22 13:09

Mike Seymour