将C ++对象(尤其是stl容器)移动到特定的内存位置

时间:2010-02-11 11:13:57

标签: c++ memory stl

我正在与内存管理器合作,有时候想要对内存进行碎片整理。基本上,我将查看内存管理器分配的对象列表并重新定位它们:

class A {
  SomeClass* data; // This member is allocated by the special manager
};

for(... each instance of A ...) 
    a.data = memory_manager.relocate(a.data);

memory_manager.relocate()memcpy()数据的内容转移到新位置,并返回指针。

尽管memcpy() C ++类通常不是惯用的,但考虑到我控制将与内存管理器一起使用的(少数)类的实现,它在这种情况下似乎是一个有用的解决方案。

问题是其中一个类使用std::map,就我而言,这是一个不透明的类。我当然不认为我可以memcpy()。在任何情况下我都可能无法使用std :: map。据我所知,它可以分配几块内存。

我能想到的最好的解决方法很简单。由于碎片化的内存管理器会将新的分配放在更有利的位置,我需要做的就是重新分配它然后删除旧的:

for(... each instance of A ...) {
    stl::map<something>* tmp = a.the_map;
    a.the_map = new stl::map<something>(tmp);
    delete tmp;
}



无论如何,这让我想知道:

C ++是否具有将对象移动/复制到特定内存位置的语义或习语?

是否可以将stl容器的内容移动到特定的内存位置?


编辑:虽然我没有指出,我显然会将一个allocator参数传递给std :: map。基于我得到的信息性答案,我意识到我在初始问题中发布的解决方法可能是减少碎片的唯一方法。通过使用map的复制构造函数(和allocator模板参数),可以正确地重新分配映射使用的所有内存。

正如评论所指出的,这主要是一个理论问题。内存碎片很少需要担心。

6 个答案:

答案 0 :(得分:4)

每次插入新的键值对时,映射都会分配一个节点来存储它。此分配如何发生的详细信息由地图使用的分配器确定。

默认情况下,当您在std::map<K,V>中创建地图时,会使用默认分配器,从而在堆上创建节点(即使用new / delete)。

您不希望如此,因此您必须创建一个自定义分配器类,该类根据内存管理器的指示创建节点。

创建一个allocator类并不简单。 This code显示了如何完成,您必须根据自己的需要进行调整。

一旦你有了你的分配器类(假设你称之为MemManagerAllocator),你必须将地图定义为std::map<K, V, MemManagerAllocator>,然后像使用常规地图一样使用它。

就个人而言,我需要有一个非常糟糕的内存碎片问题才能解决所有麻烦。

答案 1 :(得分:2)

C ++对象的内容将分散在堆中。 STL对象(例如容器或字符串等)可能会将其元数据存储在堆栈中(如果不将其放在动态内存中)...但是内容会分散在堆中。

跟踪对象的所有元素以及对这些元素的所有引用将是一项艰巨的任务。语言必须提供某种形式的“钩子”或事件,以便跟踪记忆块之间的关系。

所以不,你不能只记忆一个任意的STL对象。

Afaik overriding new并不是灵丹妙药,它是一个“全局流程”概念,因此尝试将新闻本地化为线程对象分配对是不可能的。这种本地化将使您能够将内存组合在一起。

您可以编写自己的容器,显式使用自定义内存分配器(显式,因为您提供了必要的对象标识信息),并且有一些自定义分配器。

答案 2 :(得分:2)

您可以使用展示位置吗?

void* adress = new void[size_of(*old_map_ptr)]; // or wherever you want it in your memory
map<type> new_map* = new (adress) map<type>(*old_map_ptr);
delete old_map_ptr;

答案 3 :(得分:1)

不,C ++单独管理内存,但是你可以通过实现std :: map :: allocator来帮助stl实现它,它会一直这样做,所以你不需要memcpy它。

答案 4 :(得分:0)

您没有提及您正在编码的平台,或者是否允许这样做。但是在Linux和GCC中,C ++默认分配器是用malloc实现的。

malloc可以被覆盖并替换为您自己的内部分配器。

我会按如下方式实现此malloc

在一般情况下,只需遵循原始malloc。无论何时,您都可以更改malloc函数的行为,以返回指向您准备的特殊内存区域的指针。

因此,在创建此特定std::map之前,您会给malloc一个提示。 (通过全局变量或其他一些通信手段。)

更新:alemjerus建议在同一主题上实施std::map::allocator,这是一种很多更清洁的方式,也是平台无关的。

答案 5 :(得分:0)

您可以使用placement new来定义基本std :: map对象所在的位置。但是大部分空间将通过std :: map。

分配到堆上