抛弃std::allocator以支持自定义解决方案的一些真正好的理由是什么?您是否遇到过这样的情况:它对于正确性、性能、可伸缩性等来说是绝对必要的?有什么聪明的例子吗?
自定义分配器一直是标准库的一个特性,但我并不太需要它。我只是想知道是否有人能提供一些令人信服的例子来证明他们的存在。
抛弃std::allocator以支持自定义解决方案的一些真正好的理由是什么?您是否遇到过这样的情况:它对于正确性、性能、可伸缩性等来说是绝对必要的?有什么聪明的例子吗?
自定义分配器一直是标准库的一个特性,但我并不太需要它。我只是想知道是否有人能提供一些令人信服的例子来证明他们的存在。
当前回答
正如我在这里提到的,我已经看到英特尔TBB的自定义STL分配器仅通过更改单个STL分配器就显著提高了多线程应用程序的性能
std::vector<T>
to
std::vector<T,tbb::scalable_allocator<T> >
(这是一种快速方便的方式切换分配器使用TBB的漂亮的线程私有堆;见本文件第7页)
其他回答
使用自定义分配器来使用内存池而不是堆可能会很有用。这只是众多例子中的一个。
对于大多数情况,这肯定是一个不成熟的优化。但它在某些情况下(嵌入式设备、游戏等)非常有用。
一种基本情况:当编写必须跨模块(EXE/DLL)边界工作的代码时,必须保持分配和删除只发生在一个模块中。
我在Windows上的插件架构中遇到了这种情况。例如,如果你跨DLL边界传递一个std::string,任何字符串的重新分配都发生在它起源的堆中,而不是在DLL中的堆中,这可能是不同的*。
*实际上比这更复杂,如果你动态链接到CRT,这可能会工作。但是,如果每个DLL都有一个到CRT的静态链接,那么您将陷入痛苦的世界,在那里幻影分配错误不断发生。
自定义分配器是在释放内存之前安全地擦除内存的合理方法。
template <class T>
class allocator
{
public:
using value_type = T;
allocator() noexcept {}
template <class U> allocator(allocator<U> const&) noexcept {}
value_type* // Use pointer if pointer is not a value_type*
allocate(std::size_t n)
{
return static_cast<value_type*>(::operator new (n*sizeof(value_type)));
}
void
deallocate(value_type* p, std::size_t) noexcept // Use pointer if pointer is not a value_type*
{
OPENSSL_cleanse(p, n);
::operator delete(p);
}
};
template <class T, class U>
bool
operator==(allocator<T> const&, allocator<U> const&) noexcept
{
return true;
}
template <class T, class U>
bool
operator!=(allocator<T> const& x, allocator<U> const& y) noexcept
{
return !(x == y);
}
推荐使用Hinnant的allocator样板: https://howardhinnant.github.io/allocator_boilerplate.html)
我没有使用自定义STL分配器编写c++代码,但我可以想象一个用c++编写的web服务器,它使用自定义分配器自动删除响应HTTP请求所需的临时数据。自定义分配器可以在生成响应后立即释放所有临时数据。
自定义分配器(我已经使用过)的另一个可能的用例是编写一个单元测试来证明函数的行为不依赖于它的某些输入。自定义分配器可以用任何模式填充内存区域。
前一段时间我发现这个解决方案对我非常有用:STL容器的快速c++ 11分配器。它略微加快了VS2017上的STL容器(~5倍)以及GCC上的STL容器(~7倍)。它是一种基于内存池的特殊用途的分配器。它可以与STL容器一起使用,这多亏了您所要求的机制。