如何定义自定义模拟分配器?



我试图用模拟分配器定义一个自定义的std::basic_string专门化,以记录basic_string执行的所有内存操作。

struct MockAllocator : std::allocator<char> {
char* allocate(size_t n);
void deallocate(char *p, size_t n);
};
using CustomString = std::basic_string<char, std::char_traits<char>, MockAllocator>;
CustomString str("Hello World........ (more symbols to avoid SSO)");

这个简单的代码没有调用我的分配器的方法。我甚至可以跳过定义,并且链接器不会产生任何错误。我做错了什么?

下面假设c++ 11(及以后版本)的分配器语义,旧的编译器(即使它们以其他方式实现了c++ 11)可能还没有完全实现。


你的类型不满足分配器的要求,因为它没有正确地重新绑定,所以不能保证代码的行为。

一个最小的无状态分配器是这样的:

template<typename T>
struct MockAllocator {
using value_type = T;
MockAllocator() = default;
template<typename U> MockAllocator(const MockAllocator<U>&) noexcept {}
T* allocate(std::size_t) { /*...*/ };
void deallocate(T*, std::size_t) { /*...*/ };
};
template<typename T, typename U>
inline bool operator==(const MockAllocator<T>&, const MockAllocator<U>&) noexcept { return true; };
template<typename T, typename U>
inline bool operator!=(const MockAllocator<T>&, const MockAllocator<U>&) noexcept { return false; };

,作为MockAllocator<char>传递给std::basic_string

模板参数是必需的。分配器必须始终可重新绑定到其他对象类型,这对于这种形式的模板自动起作用。否则必须提供rebind成员。

==!=操作符是必需的。它们决定两个分配器是否可以释放由另一个分配器分配的内存。对于这样一个简单的无状态分配器,它们可以分别返回truefalse。自c++ 20以来,!=重载是可选的。

对于更复杂的分配器,特别是有状态的分配器,可能需要std::allocator_traits默认的其他成员才能使其正常工作。

不需要继承std::allocator。事实上,在c++ 20之前,从std::allocator继承将导致它的rebind也被继承,这将错误地重新绑定到std::allocator</*...*/>而不是MockAllocator,这违反了分配器的要求。由于c++ 20的std::allocator没有rebind,所以你的非模板MockAllocator将完全不可重新绑定,再次违反了要求。

最后一部分可能是你看到你所做的行为的原因。libstc++在内部重新绑定了char的分配器,这对于一个合适的分配器来说应该是完全没问题的,但是您的分配器重新绑定到std::allocator<char>而不是MockAllocator,因此它将有效地只使用std::allocator<char>

相关内容

  • 没有找到相关文章

最新更新