如何在现代 C++ 中使用分配器
How to use allocators in modern C++
根据我在 http://en.cppreference.com/w/cpp/memory/allocator 中读到的内容,分配器的大多数功能现在都将被弃用。问题是,应该如何在新代码中使用分配器? "right" 现在的方法是什么?
根据我在文档中的推断,construct
是分配器特征的一部分,而不是分配器本身。
我正在构建一个自定义容器,这里是构造函数的一个非常简单的版本,这是新设计的一个很好的用法吗?
container::container(std::size_t size, T const& value, Allocator const& allocator) : allocator_(allocator){
data_ = std::allocator_traits<Alloc>::allocate(allocator_, size);
for(auto ptr = data_; ptr != data_ + size; ++ptr){
std::allocator_traits<Allocator>::construct(allocator_, ptr, value)
}
}
我尝试在循环中使用一种算法(如 std::for_each
),但我没能在不获取地址的情况下使用算法(operator&
)。
在哪里可以找到现代分配器的完整示例?
经过一些调整后,我找到了一种使用算法而不是原始循环(可以将执行策略传递到其中)的方法。我不太确定,但可能是这样的:
data_ = std::allocator_traits<Allocator>::allocate(allocator_, size);
std::for_each([policy? deduced from allocator?,]
boost::make_counting_iterator(data_),
boost::make_counting_iterator(data_ + size),
[&](auto ptr){std::allocator_traits<Allocator>::construct(allocator_, ptr, value);}
);
是的,目前的方法是通过std::allocator_traits
。这样您就可以支持 "minimal allocator interface"。
http://en.cppreference.com/w/cpp/concept/Allocator
Some requirements are optional: the template std::allocator_traits
supplies the default implementations for all optional requirements, and all standard library containers and other allocator-aware classes access the allocator through std::allocator_traits
, not directly.
如果您观察 std::allocator_traits
成员函数和类型定义,您会发现它们正在检测是否存在适当的 function/types 并在可能的情况下通过它们进行调度。
如果您已经在使用 std::allocator_traits
,则弃用和未来可能的移除不会有任何改变,因为它仅适用于 std::allocator
及其成员 functions/typedefs。
现在,如果您问我,for 循环没有任何问题,使用 std::for_each
对您没有任何好处。有几个uninitialized_*
函数,但是直接用了placement new。如果您真的很在意,可以将此代码提取到单独的 construct_range
函数中。
还有一个异常安全问题 - 如果其中一个构造函数抛出,您需要销毁较早的元素以满足强异常保证并释放内存(如果构造函数不会调用析构函数投掷)
根据我在 http://en.cppreference.com/w/cpp/memory/allocator 中读到的内容,分配器的大多数功能现在都将被弃用。问题是,应该如何在新代码中使用分配器? "right" 现在的方法是什么?
根据我在文档中的推断,construct
是分配器特征的一部分,而不是分配器本身。
我正在构建一个自定义容器,这里是构造函数的一个非常简单的版本,这是新设计的一个很好的用法吗?
container::container(std::size_t size, T const& value, Allocator const& allocator) : allocator_(allocator){
data_ = std::allocator_traits<Alloc>::allocate(allocator_, size);
for(auto ptr = data_; ptr != data_ + size; ++ptr){
std::allocator_traits<Allocator>::construct(allocator_, ptr, value)
}
}
我尝试在循环中使用一种算法(如 std::for_each
),但我没能在不获取地址的情况下使用算法(operator&
)。
在哪里可以找到现代分配器的完整示例?
经过一些调整后,我找到了一种使用算法而不是原始循环(可以将执行策略传递到其中)的方法。我不太确定,但可能是这样的:
data_ = std::allocator_traits<Allocator>::allocate(allocator_, size);
std::for_each([policy? deduced from allocator?,]
boost::make_counting_iterator(data_),
boost::make_counting_iterator(data_ + size),
[&](auto ptr){std::allocator_traits<Allocator>::construct(allocator_, ptr, value);}
);
是的,目前的方法是通过std::allocator_traits
。这样您就可以支持 "minimal allocator interface"。
http://en.cppreference.com/w/cpp/concept/Allocator
Some requirements are optional: the template
std::allocator_traits
supplies the default implementations for all optional requirements, and all standard library containers and other allocator-aware classes access the allocator throughstd::allocator_traits
, not directly.
如果您观察 std::allocator_traits
成员函数和类型定义,您会发现它们正在检测是否存在适当的 function/types 并在可能的情况下通过它们进行调度。
如果您已经在使用 std::allocator_traits
,则弃用和未来可能的移除不会有任何改变,因为它仅适用于 std::allocator
及其成员 functions/typedefs。
现在,如果您问我,for 循环没有任何问题,使用 std::for_each
对您没有任何好处。有几个uninitialized_*
函数,但是直接用了placement new。如果您真的很在意,可以将此代码提取到单独的 construct_range
函数中。
还有一个异常安全问题 - 如果其中一个构造函数抛出,您需要销毁较早的元素以满足强异常保证并释放内存(如果构造函数不会调用析构函数投掷)