您可以。
你写了std::vector<T>
,但std::vector
需要两个模板参数,不只是一个。第二个模板参数指定要使用的分配器类型,并且构造函数的重载允许传入该分配器类型的自定义实例。
因此,您只需编写一个分配器,尽可能使用您自己的内部缓冲区,并在您自己的内部缓冲区已满时回退到询问默认分配器。
默认分配器不可能希望处理它,因为它不知道哪些内存位可以被释放,哪些不能。
样品状态分配器与含有已构建的元件不应该由该载体被覆盖,包括一个大的疑难杂症的示范内部缓冲器:
struct my_allocator_state {
void *buf;
std::size_t len;
bool bufused;
const std::type_info *type;
};
template <typename T>
struct my_allocator {
typedef T value_type;
my_allocator(T *buf, std::size_t len)
: def(), state(std::make_shared<my_allocator_state, my_allocator_state>({ buf, len, false, &typeid(T) })) { }
template <std::size_t N>
my_allocator(T(&buf)[N])
: def(), state(std::make_shared<my_allocator_state, my_allocator_state>({ buf, N, false, &typeid(T) })) { }
template <typename U>
friend struct my_allocator;
template <typename U>
my_allocator(my_allocator<U> other)
: def(), state(other.state) { }
T *allocate(std::size_t n)
{
if (!state->bufused && n == state->len && typeid(T) == *state->type)
{
state->bufused = true;
return static_cast<T *>(state->buf);
}
else
return def.allocate(n);
}
void deallocate(T *p, std::size_t n)
{
if (p == state->buf)
state->bufused = false;
else
def.deallocate(p, n);
}
template <typename...Args>
void construct(T *c, Args... args)
{
if (!in_buffer(c))
def.construct(c, std::forward<Args>(args)...);
}
void destroy(T *c)
{
if (!in_buffer(c))
def.destroy(c);
}
friend bool operator==(const my_allocator &a, const my_allocator &b) {
return a.state == b.state;
}
friend bool operator!=(const my_allocator &a, const my_allocator &b) {
return a.state != b.state;
}
private:
std::allocator<T> def;
std::shared_ptr<my_allocator_state> state;
bool in_buffer(T *p) {
return *state->type == typeid(T)
&& points_into_buffer(p, static_cast<T *>(state->buf), state->len);
}
};
int main()
{
int buf [] = { 1, 2, 3, 4 };
std::vector<int, my_allocator<int>> v(sizeof buf/sizeof *buf, {}, buf);
v.resize(3);
v.push_back(5);
v.push_back(6);
for (auto &i : v) std::cout << i << std::endl;
}
输出:
1
2
3
4
6
5
的push_back
适合旧的缓冲区,所以建筑被绕过。当添加6
时,将分配新内存,并且所有内容都按照正常方式开始工作。你可以通过向你的分配器添加一个方法来避免这个问题,以表明从那时起,建设不应该被绕过。
points_into_buffer
原来是最难写的部分,我从我的回答中忽略了这一点。预期的语义应该从我如何使用它中显而易见。请参阅my question here以获得便携式实现,或者如果您的实现允许,请使用其他问题中较简单的版本之一。顺便说一下,我不是很满意一些实现如何使用rebind
这样的方式,以避免存储运行时类型信息以及状态,但是如果你的实现不需要这样做,那么你可以通过使状态成为模板类(或嵌套类)来使其更简单一些。
来源
2015-01-01 11:36:26
hvd
为什么不直接将元素顺序移动到矢量中?想必你把它们放到一个矢量中,以便以后可以调整集合的大小,所以你预计它们会被移动,对吗?如果无论如何会发生这种情况,可能会多次,那么避免它发生一次可能是一个不成熟的优化。 –
@克里斯贝克:不,这不是我把它们放在向量中的原因。假设我有一些STLish代码需要一个向量,而不是一个原始数组。 – einpoklum
我想你不能使用'std :: array'或者是因为动态调整大小或者是可能的?也许在你的原始缓冲区中有某种类型的包装类型,它具有类似于STL的接口,足以满足你的需要。我的猜测是,从头开始做这样的事情可能更容易,然后搞乱分配器 –