Использование boost.pool вместо ‘new’ для контейнера объектов

В кодовой базе, над которой я работаю, в настоящее время есть код, который делает это часто:

// In the header:
class Label
{
public:
void ParseText();

private:
Letter* m_myArray;
};

// In the CPP:
void ParseText()
{
delete[] m_myArray;
m_myArray = new Letter[string_length];
// ......
}

Обычно каждый раз, когда строка изменяется в метке, мы удаляем старый набор буквенных объектов и создаем их заново. Эти буквенные объекты несколько легковесны, но так как это часто случается, я не могу просто использовать std::vector<Letter> так как каждый push_back() приведет к копии. Я бы тоже хотел избежать копии.

Поможет ли здесь использование Boost Pool? Я могу себе представить, как это делается (это псевдокод, поскольку я пока не уверен, как точно использовать пул повышения):

// In the header:
class Label
{
public:
void ParseText();

private:
std::vector<Letter*> m_myArray;
boost::object_pool m_pool;
};

// In the CPP:
void ParseText()
{
// Loop through each element in m_myArray and call pool::free
m_myArray.clear();

// Loop each letter and create a new Letter object in the container
for( ... ) {
m_myArray.push_back(m_pool.malloc()); // Not sure how to handle constructor params
}

// ......
}

Это позволит избежать копирования и избежать частого размещения. Тем не менее, я снизил удобство сопровождения кода, поскольку при добавлении / удалении элементов из вектора задействовано так много шаблонов.

Я думал об использовании boost :: ptr_vector с пользовательским средством удаления, но не уверен, что это сильно поможет. Это помогает очистить, но я все еще должен позвонить pool::malloc() каждый раз, когда я делаю push_back.

Использование собственного распределителя с std :: vector, по-видимому, также не имеет смысла, так как он в любом случае предварительно выделен и не будет уменьшаться в размере.

Может ли кто-нибудь помочь мне найти «лучшее» решение этой проблемы?

1

Решение

То, что я думаю, я бы сделал, это использовать vector а также resize минимизировать количество выделений и разрешить повторное использование писем. Итак, у нас есть что-то вроде этого:

// In the header:
class Label
{
public:
void ParseText();

private:
std::vector<Letter> m_myArray;
};

// In the CPP:
void ParseText()
{
m_myArray.resize(string_length);
// ......
}

С таким подходом, как многие Letter объекты, насколько это возможно, повторно используются из предыдущего экземпляра. Вы даже можете позвонить reserve в Label конструктор для предварительного выделения достаточного пространства для предотвращения копирования / перемещения объектов Letter в дальнейшем.

0

Другие решения

Я думаю, что пул памяти будет иметь значение в некоторых ситуациях. поскольку boost::object_pool<> не предоставляет метод для выделения массива объектов, поэтому я бы использовал boost::pool<> который на самом деле является основным пулом памяти boost::object_pool<>,

#include <cstdio>
#include <ctime>
#include "boost/pool/pool.hpp"
struct Letter{
float a, b, c;
int *p;
};

class Label
{
public:
Label() : m_myArray(NULL), string_length(1), last_size(0){}

void set_size(size_t n)
{
last_size = string_length; // use last_size to store the number of last allocation, just for test.
string_length = n;
}
void ParseText()
{
delete[] m_myArray;
m_myArray = new Letter[string_length];
}

void ParseText_pool();

private:
Letter* m_myArray;
size_t string_length;
size_t last_size; //boost::pool<>::ordered_free need the size
};

boost::pool<> p(sizeof(Letter));

void Label::ParseText_pool()
{
if(m_myArray)
p.ordered_free(m_myArray, last_size); // ordered_free need the right size
m_myArray = (Letter*)p.ordered_malloc(string_length); // if you need call the ctor, use placement new.
}

int main()
{
Label l;

float startTime = (float)clock()/CLOCKS_PER_SEC;

for(int i = 1; i < 1000000; ++i)
{
l.set_size(i%100 + 1);
l.ParseText();
}

float endTime = (float)clock()/CLOCKS_PER_SEC;

printf("without pool, time: %f\n", endTime - startTime);

Label l2;
startTime = (float)clock()/CLOCKS_PER_SEC;

for(int i = 1; i < 1000000; ++i)
{
l.set_size(i%100 + 1);
l2.ParseText_pool();
}

endTime = (float)clock()/CLOCKS_PER_SEC;

printf("with pool, time: %f\n", endTime - startTime);
};

Беги на моей машине и coliru, это показывает, что чем чаще происходит выделение ресурсов, тем больше преимущество использования пула памяти.

0

По вопросам рекламы [email protected]