在我正在处理的代码库中,它目前有代码经常执行此操作:
// 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与自定义删除器一起使用,但不确定这是否有用。它有助于清理,但每次执行push_back时我仍然需要调用pool::malloc()
。
使用带有std :: vector的自定义分配器似乎没有任何意义,因为它无论如何都是预先分配的,并且不会缩小。
任何人都可以帮我找出这个问题的“最佳”解决方案吗?
答案 0 :(得分:0)
我认为我会做的是使用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对象进行任何复制/移动。
答案 1 :(得分: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上运行,它显示分配越频繁,使用内存池的优势就越大。