【问题标题】:What data structure can I use to free memory within a contiguous stretch of memory?我可以使用什么数据结构来释放连续内存中的内存?
【发布时间】:2019-12-04 06:22:14
【问题描述】:

我想模拟一段时间内的人口并保留仍然活着的个体的家谱(我不需要保留有关死去血统的数据)。世代是离散且不重叠的。为简单起见,我们假设繁殖是无性的,并且每个个体只有一个父母。这里是一堂课Individual

class Individual
{
public:
   size_t nbChildren;
   const Individual* parent;

   Individual(const Individual& parent);
};

在我的Population 类中,我将有一个用于当前后代和当前父母(当前父母是上一代的后代)的向量。

class Population
{
private:
  std::vector<Individual*> currentOffsprings;
  std::vector<Individual*> currentParents;

public:
  addIndividual(const Individual& parent) // Is called from some other module
  {
      Individual* offspring = new Individual(parent);
      currentOffsprings.push_back(offspring);
  }

  void pruneDeadLineages() // At the end of each generation, get rid of ancestors that did not leave any offsprings today
  {
    // Collect the current parents that have not left any children in the current generation of offsprings
    std::queue<Individual*> individualsWithoutChildren; // FIFO structure
    for (auto& currentParent : currentParents)
    {
      if (currentParent->nbChildren() == 0)
      {
        individualsWithoutChildren.push(currentParent);
      }
    }

    // loop through the FIFO to get rid of all individuals in the tree that don't have offspring in this generation
    while (individualsWithoutChildren.size() != 0)
    {
      auto ind = individualsWithoutChildren.pop_front();
      if (ind->nbChildren == 0)
      {
        ind->parent.nbChildren--;
        if (ind->parent.nbChildren == 0)
        {
          individualsWithoutChildren.push(ind->parent);
        }
        delete ind;
      }
    }
  }

  void newGeneration() // Announce the beginning of a new generation from some other module
  {
    currentParents.swap(currentOffsprings); // Set offsprings as parents
    currentOffsprings.resize(0);            // Get rid of pointers to parents (now grand parents)
  }

  void doStuff() // Some time consuming function that will run each generation
  {
    for (auto ind : currentOffspings)
    {
      foo(ind);
    }
  }
};

假设我的代码的慢速部分将循环通过 doStuff 方法中的个体,我想在内存中保持个体连续,因此

  std::vector<Individual*> currentOffsprings;
  std::vector<Individual*> currentParents;

会变成

  std::vector<Individual> currentOffsprings;
  std::vector<Individual> currentParents;

现在的问题是我不想为在当前一代中没有留下任何后代的祖先消耗内存。换句话说,我不想为每一代保留人口中每代个体数量的整个长度向量。我想我可以实现一个 Individual 的析构函数,它什么都不做,这样祖父代的 Individuals 就不会在 void Population::newGeneration() 中的 currentOffsprings.resize(0); 行被杀死。然后在void Population::pruneDeadLineages() 中,我将使用Individual::destructor() 方法显式删除个人,而不是使用deleteIndividual::~Individual()

傻吗?它会是内存安全的(或屈服于分段错误或内存泄漏)吗?我还有什么其他选择 1) 确保当前世代的个体在记忆中是连续的,并且 2) 我可以为没有留下任何后代的祖先释放这段连续记忆中的记忆?

【问题讨论】:

  • 共享指针或弱指针是否适合您?可以在一定时间间隔内运行一些简单的清理,同时保持向量内存预分配到位
  • @PaulRenton 我没有使用共享指针和弱指针的经验,但我觉得它们无助于确保Individuals 在内存中是连续的,但我可能错了。谢谢
  • 如果您希望它是连续的,则分配这些对象的池并使用弱指针引用从那里绘制指针。或者,覆盖一个新的运算符并创建一个内存池,当您分配您关心的对象时,该内存池保证是连续的。

标签: c++ memory data-structures memory-management tree


【解决方案1】:

我真的不明白您为什么需要将您的Individuals 连续存储在内存中。

由于您必须在每一代中删除其中一些并添加其他,您必须对整个Individuals 执行重新分配,以使它们在内存中保持连续。

但无论如何,我不会质疑你想做什么。


我认为最简单的方法是让std::vector 为你做事。不需要指针。

在每一代中,您将后代从currentOffsprings 移动到currentParents,然后您将clear() 移动到currentOffsprings
然后,对于当前一代中没有任何子代的每个父代,您可以使用 erase() from std::vector 删除它们,从而让 std::vector 负责保持其元素连续。

超过 100 个单词,例如:

void Population::newGeneration()
{
    currentParents.swap(currentOffsprings);
    currentOffsprings.clear();
}

void Population::pruneDeadLineages()
{
    currentParents.erase(std::remove_if(currentParents.begin(), currentParents.end(), [](const Individual & ind){return ind.nbChildren == 0;}), currentParents.end());
}

当然它假设父母和后代在Population中定义为:

std::vector<Individual> currentParents;
std::vector<Individual> currentOffsprings;

注意:由于std::remove_if将要删除的元素移动到容器的末尾,要保持的元素保持连续,因此在执行擦除时不会重新分配。

这样你的两个要求(在内存中保持Individuals 连续并摆脱死去的血统)将被满足,而不会用析构函数做奇怪的事情,...

但由于您有两个std::vector,因此您可以确保将currentOffsprings 连续存储在内存中,currentParents 也是如此。
但是这两个std::vectors 绝对不能保证彼此相邻(但我认为您已经意识到这一点并且这不是您想要的)。

如果我误解了您的实际问题,请告诉我

【讨论】:

    猜你喜欢
    • 2019-03-11
    • 1970-01-01
    • 2015-06-07
    • 1970-01-01
    • 2015-06-26
    • 2012-04-10
    • 2020-03-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多