为什么C++ 14中没有std :: allocate_unique函数?

hat*_*cat 17 c++ std c++14

为什么在shared_ptr没有allocate_unique的unique_ptr情况下有allocate_shared?
我想使用自己的分配器创建一个unique_ptr:我是否必须自己分配缓冲区然后将其分配给unique_ptr?
这似乎是一个明显的成语.

Mik*_*our 16

为什么shared_ptrallocate_sharedunique_ptr没有allocate_unique

shared_ptr需要它,以便它可以使用分配器分配其内部共享状态(引用计数和删除)以及共享对象.unique_ptr只管理对象; 所以不需要为自己提供分配器unique_ptr,也不需要allocate功能.

(make_unique由于同样的原因也没有必要,这可能是为什么它没有在C++ 11中出现的原因,但为了一致性而被大众需求添加到C++ 14中.也许相同的需求会增加allocate_unique未来的标准.)

我是否必须自己分配缓冲区然后将其分配给unique_ptr?

是.或者你可以写自己的allocate_unique; 不同的是allocate_shared,将它与unique_ptr自身分开实施是可能的,而且相当简单.(正如评论中所提到的,你必须确保它为分配器使用了一个合适的删除器;默认的删除器将使用delete并且可怕的错误).

这似乎是一个明显的成语.

确实.但许多其他成语也是如此,并非所有事物都可以(或应该)标准化.

有关目前缺乏的更正式的理由allocate_unique,请参阅提案make_unique,特别是第4节(自定义删除器).

  • +1.提案中提到的类型擦除方面是最重要的恕我直言,什么类型将`allocate_unique`返回? (4认同)

Jon*_*ely 16

我是否必须自己分配缓冲区然后将其分配给unique_ptr?

不只是一个缓冲区,一个指向对象的指针.但是对象可能需要被分配器破坏,内存肯定需要由分配器解除分配,所以你还需要传递分配器unique_ptr.它不知道如何使用分配器,因此您需要将其包装在自定义删除器中,并且它将成为该unique_ptr类型的一部分.

我认为通用解决方案看起来像这样:

#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;
}
Run Code Online (Sandbox Code Playgroud)