【问题标题】:allocator_traits::construct() vs allocator_traits::allocate()allocator_traits::construct() 与 allocator_traits::allocate()
【发布时间】:2013-07-25 17:08:33
【问题描述】:

C++11 提供std::allocator_traits 类作为使用分配器的标准方式。静态函数std::allocator_traits::construct() 采用指针 指向应该构造对象的位置。然而,std::allocator_traits::allocate() 静态函数返回一个 allocator::pointer 值,它只需要表现得像一个指针,但不一定是一个(通常,尽管std::allocator::pointer 必须是一个指针)。

如果分配和构造静态方法通常适用于不兼容的类型,应该如何使用它们?只有在pointer 类型实际上可以转换为普通的普通指针时才能使用它们吗?

【问题讨论】:

  • +1 目前这是一个非常有见地的问题。很少有 C++ 程序员探索这些领域。实施者必须这样做。这让我问了一个问题:你是 std::lib 的实现者吗?
  • @HowardHinnant:谢谢!这个问题与一个小型向量类的设计有关,在std::vector 上有一些额外的花里胡哨(例如,自动使用最多几个元素的静态存储,支持 SSE 和其他向量指令等)。只是想尝试在分配器支持方面以“正确”的方式做事。

标签: c++ memory-management c++11


【解决方案1】:

有两种技术可以做到这一点,具体取决于您目前的情况。

如果你有一个左值表达式,比如节点中的值字段,那么你可以像这样使用 std::addressof:

allocator_traits<allocator_type>::construct(alloc, std::addressof(ptr->value), ...);

其中ptrallocator_type::pointer

但是,如果您没有要取消引用的字段并且想要将 allocator_type::pointer 转换为 T*,则需要先实现一个技巧:

template <class T>
inline
T*
to_raw_pointer(T* p) noexcept
{
    return p;
}

template <class Pointer>
inline
typename std::pointer_traits<Pointer>::element_type*
to_raw_pointer(Pointer p) noexcept
{
    return p != nullptr ? ::to_raw_pointer(p.operator->())
                        : nullptr;
}

现在你可以说:

allocator_traits<allocator_type>::construct(alloc, to_raw_pointer(ptr), ...);

【讨论】:

  • 哦,哇,永远学不完...operator-&gt;() 的语义令人难以置信:D
  • 为什么::前面要写to_raw_pointer(p.operator-&gt;())?是否存在 ADL 会造成干扰的危险,还是只是一种习惯?我认为当两个重载都在同一个命名空间中时,这无关紧要。
  • 我认为查找只会找到第二个重载是偏执狂,但在测试时我发现它毕竟不需要。在编写成员交换时,我偶尔会偶然发现类似的问题,因此养成了总是排位赛的习惯,除非我真的希望 ADL 接管。
【解决方案2】:

从C++20开始,有std::to_address,在P0653提出。

【讨论】:

    猜你喜欢
    • 2020-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多