В кодовой базе, над которой я работаю, в настоящее время есть код, который делает это часто:
// 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, по-видимому, также не имеет смысла, так как он в любом случае предварительно выделен и не будет уменьшаться в размере.
Может ли кто-нибудь помочь мне найти «лучшее» решение этой проблемы?
То, что я думаю, я бы сделал, это использовать 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 в дальнейшем.
Я думаю, что пул памяти будет иметь значение в некоторых ситуациях. поскольку 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, это показывает, что чем чаще происходит выделение ресурсов, тем больше преимущество использования пула памяти.