C++;:如何处理未使用的空向量消耗的RAM? 我有一个C++软件,它执行基于代理的模拟。在模拟中,有群体s包含斑块es,其中个体s包含两个单倍型s。每个单倍型包含12个载体,每个载体用于跟踪不同类型的基因 class Haplotype { std::vector<A> genesA; std::vector<B> genesB; std::vector<C> genesC; std::vector<D> genesD; .... }; 类单倍型 { std::载体基因; std::载体基因b; std::载体基因; std::载体基因; .... };
然而,在实践中,用户永远不会使用超过一种或两种类型的基因。这意味着每个未使用的向量都会消耗几个字节(至少两个指针)。对于具有大量基因和少量C++;:如何处理未使用的空向量消耗的RAM? 我有一个C++软件,它执行基于代理的模拟。在模拟中,有群体s包含斑块es,其中个体s包含两个单倍型s。每个单倍型包含12个载体,每个载体用于跟踪不同类型的基因 class Haplotype { std::vector<A> genesA; std::vector<B> genesB; std::vector<C> genesC; std::vector<D> genesD; .... }; 类单倍型 { std::载体基因; std::载体基因b; std::载体基因; std::载体基因; .... };,c++,algorithm,design-patterns,C++,Algorithm,Design Patterns,然而,在实践中,用户永远不会使用超过一种或两种类型的基因。这意味着每个未使用的向量都会消耗几个字节(至少两个指针)。对于具有大量基因和少量个体的模拟,这是可以忽略不计的。然而,对于基因少、个体多的模拟来说,这些额外的字节可能开始起作用。性能(CPU时间和RAM)至关重要 有没有一个好的设计模式可以让我处理这个问题?只需按需将载体添加到单倍型 我不知道它是否是您正在寻找的,但我认为,您可以存储一个只包含有用向量的向量向量(使用多态性),而不是存储12个只包含一个或两个有用向量的向量 例如,为基因类
个体的模拟,这是可以忽略不计的。然而,对于基因少、个体多的模拟来说,这些额外的字节可能开始起作用。性能(CPU时间和RAM)至关重要
有没有一个好的设计模式可以让我处理这个问题?只需按需将载体添加到单倍型
我不知道它是否是您正在寻找的,但我认为,您可以存储一个只包含有用向量的向量向量(使用多态性),而不是存储12个只包含一个或两个有用向量的向量
例如,为基因类型创建基类:
class Gene
{
// Make it pure virtual (abstract) for example
};
然后创建继承该基类的12种不同类型的基因:
class A : public Gene // Gene type number 1
{
// ...
};
...
class L : public Gene // Gene type number 12
{
};
因此,你所有的12种基因都是基因
然后,在单倍型
中,可以按如下方式存储有用的基因:
class Haplotype
{
std::vector<std::vector<Gene*>> genes;
};
类单倍型
{
std::载体基因;
};
这样,您只存储在载体中有用的基因,而不存储其他基因。当然,这种使用多态性的设计意味着存储指针而不是值
您可以在Haplotype
中添加一个方法,该方法检索其组件的真实类型(成功的动态类型转换),使其从“用户端”不易察觉
我不知道这个解决方案是否对你有好处,但我希望它能有所帮助
编辑:
如果您在C++17之前,因此无法使用std::variant
,我认为这可能是另一种选择。我认为无论您做什么,都必须为即将到来的数据保留一些空间
向量有可能“浪费”一些未使用的空间。此外,对象本身使用一些内存,如您所说
但是,当您使用阵列时,您拥有完全控制权。
带有std::vector[]基因代码>您可以完全使用所需的内存。
但现在您必须知道哪个索引表示哪种类型(A、B、C…)。这些信息会再次消耗你的内存。。。
此外,如果要添加另一个阵列,还必须复制并重新分配该阵列
通过使用指针并使用nullptr
初始化它们,可以避免为每个向量使用分配的内存。然后按需分配。
这样只会浪费指针的空间。
按照当前的实现方式,您将初始化每个向量对象(,可能还有一些保留空间)。如果所有基因类型的大小大致相同,那么这样做可能是一个胜利:
union基因
{
A A;
B B;
C C;
D;
};
类单倍型
{
std::载体基因;
中部本德国际机场;
公众:
一个getA(intidx){
返回基因[idx].a;
}
B getB(intidx){
返回基因[idx+aEnd].b;
}
C getC(int idx){
返回基因[idx+bEnd].c;
}
D getD(intidx){
返回基因[idx+cEnd].d;
}
};
向载体中添加一个给定类型的新基因可以在固定时间内完成(你不需要把所有的东西都推回去),只要你不关心单个类型的顺序
例如,如果你需要添加一个B,你可以将它移动到第一个C的位置,然后将其移动到第一个D的位置,然后将其推到末端。然后,您将依次递增bEnd
和cEnd
例如:
最初:[A1、A2、A3、B1、B2、C1、C2、C3、C4、D1、D2、D3、D4、D5]
在折弯处添加新的B:[A1、A2、A3、B1、B2、B3、C2、C3、C4、D1、D2、D3、D4、D5]
更换收回的C:[A1、A2、A3、B1、B2、B3、C2、C3、C4、C1、D2、D3、D4、D5]
在末尾添加被逐出的D:[A1、A2、A3、B1、B2、B3、C2、C3、C4、C1、D2、D3、D4、D5、D1]
要在固定时间内去除一个基因,你可以反过来做类似的事情。关键是要保持不变,即所有As都在所有Bs之前,所有Cs之前,所有Ds之前
此方案允许您以较少的开销获得成功:每种类型只有一个int(用于存储结束索引),以换取更难看的代码,在添加或删除基因时有一点额外的时间开销,以及无法保持每组基因的插入顺序。这些缺点是否值得,取决于你
此外,如果类型的大小有显著差异,则此设计将导致每个元素的开销,因为联合必须至少与其最大的成员一样大。将std::vector只要每个类型的大小相同,变体就可以获胜。如果不是,空向量的开销通常在两个指针和一个大小上。std::variant
将为向量中的每个元素带来一些恒定的开销。我认为这个问题有点不够明确。你会有多少个单倍型?A、B、C……的尺寸是多少。。。等你希望用它们做什么std::vector
在我的系统上是24字节。如果你真的有这么多的单倍型,以至于每个单倍型的288字节的开销是不可接受的,那么你可能会想要一些手工优化的东西,考虑到数据访问模式…@Remi.b什么是A、b、C等类型?这需要