您可以。
你寫了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的接口,足以滿足你的需要。我的猜測是,從頭開始做這樣的事情可能更容易,然後搞亂分配器 –