我有一大堆数千个对象,我按顺序迭代,数万到数十万(有时是数百万)次。我想连续存储这些对象,以减少我的缓存未命中数。我也希望从中获得多态行为。我的想法是分配一大块内存,在适当的位置构建它们,并在向量中存储指向每个对象的指针。一些示例代码如下所示:
#include <iostream>
#include <vector>
#include <cstdlib>
using namespace std;
class Base
{
public:
virtual ~Base() {}
Base(int x) : x_(x) {}
Base& operator=(const Base& b) { x_ = b.x(); return *this; }
inline int x() const { return x_; }
virtual void foo() const { cout << "Base::foo() = " << x() << "\n"; }
private:
int x_;
};
class Derived : public Base
{
public:
~Derived() {}
Derived(int x, int y) : Base(x), y_(y) {}
Derived& operator=(const Derived& d) { Base::operator=(d); y_ = d.y();
return *this; }
inline int y() const { return y_; }
void foo() const { cout << "Derived::foo() = " << x() << ", " << y() <<
"\n"; }
private:
int y_;
};
constexpr size_t max_class_hierarchy_size()
{
return (sizeof(Base) > sizeof(Derived)) ? sizeof(Base) :
sizeof(Derived);
}
enum class DynamicType : unsigned { BASE, DERIVED };
int main()
{
const static unsigned int n = 5;
const int xs[] = {1, 3, 2, -4, 5};
const int ys[] = {-4, 7, 12, 15, 3};
const DynamicType tps[] = {DynamicType::BASE, DynamicType::DERIVED,
DynamicType::DERIVED, DynamicType::DERIVED,
DynamicType::BASE};
cout << "sizeof(Base) = " << sizeof(Base) << "\n";
cout << "sizeof(Derived) = " << sizeof(Derived) << "\n";
cout << "max size() = " << max_class_hierarchy_size() << "\n";
void* main_mem_pool = malloc(n * max_class_hierarchy_size());
Base* mem_pool = static_cast<Base*>(main_mem_pool);
vector<Base*> bs(n);
for (unsigned i = 0; i < n; ++i)
{
bs[i] = mem_pool;
switch(tps[i])
{
case DynamicType::BASE:
{
Base* new_loc_base = static_cast<Base*>(mem_pool);
new (new_loc_base) Base(xs[i]);
new_loc_base++;
mem_pool = static_cast<Base*>(new_loc_base);
break;
}
case DynamicType::DERIVED:
{
Derived* new_loc_derived = static_cast<Derived*>(mem_pool);
new (new_loc_derived) Derived(xs[i], ys[i]);
new_loc_derived++;
mem_pool = static_cast<Base*>(new_loc_derived);
break;
}
default:
cerr << "Type: " << static_cast<unsigned>(tps[i])
<< " not defined. Exitting...\n";
exit(1);
}
}
for (const auto& b : bs) b->foo();
for (int i = n-1; i >= 0; --i) bs[i]->~Base();
free(main_mem_pool);
return 0;
}
我为一个冗长的例子道歉,但这给了我期待的行为。唯一的问题是valgrind告诉我,我有内存泄漏。 Valgrinds输出说我有3个分配,只有2个解除分配。我不会看到它。
为什么这是内存泄漏?有没有更好的方法来解决这个问题?有没有比malloc / free / manual调用析构函数更简单的方法来分配/解除分配?
答案 0 :(得分:1)
使用valgrind --leak-check=yes --leak-check=full
选项运行此命令,因为valgrind的原始诊断建议您这样做,将向您显示额外的分配来自C ++标准库中的某些启动代码,并且与您的代码无关
运行时库在初始化时分配一些静态存储是很常见的,它们不会在终止时释放。你从valgrind得到的原始输出可能是这样的:
==8498== LEAK SUMMARY:
==8498== definitely lost: 0 bytes in 0 blocks
==8498== indirectly lost: 0 bytes in 0 blocks
==8498== possibly lost: 0 bytes in 0 blocks
==8498== still reachable: 72,704 bytes in 1 blocks
==8498== suppressed: 0 bytes in 0 blocks
除非在前两个类别中出现某些内容,否则通常不是真正的内存泄漏。大多数发行版都使用抑制文件配置valgrind,该文件忽略标准系统库在初始化时捕获的已知内存块的警告,并且不需要在退出时进行清理。 Gnome库是最糟糕的攻击者,C ++标准库通常非常干净,但我想当前版本的libstdc++
会留下一些东西,并且各种发行版valgrind安装尚未更新以解决这个问题。 / p>