减少内存使用

reducing memory usage

本文关键字:内存      更新时间:2023-10-16

我正在开发一个项目,我在其中使用了许多类。对于创建类,我使用了new操作符…例如,在banana类中,我有一个apple类的实例变量......

这是我想说的话的缩小版&不代表代码字对字…所以请不要指出语法错误……但是试着理解方法

头文件(banana.h):

static int counter = 0;
class banana
{
  public:
  apples *ap_obj;//(apple is a class defined another file apples.cpp)
  int *index;
}

in banana.cpp:

class banana
{
  banana::banana(void)
  {
    ap_obj = new apples;
    index = new int;
    *index = ++counter;
  }
};

我的第一个问题是,我的方法在内存效率方面是否正确?(我知道我肯定没有任何运行时错误)

我的第二个问题是,我想通过使用索引(请注意,每个香蕉对象都有一个唯一的索引)变量来访问任何类的一个方法中的香蕉对象。为此,我正在考虑使用另一个类注册表(因为我想存储许多类对象的索引)。我正在考虑将任何类的第一个对象的指针存储在我的注册表类中。,为了访问类的任何第n个对象的指针,我计划使用索引变量对第一个对象使用指针算术…示例

class registry
{
  banana *base_obj;//this value will be initialised when i create the 1st object of banana class
  banana *registry::get_nth_object(int shift);
  {
    return *(base_obj + shift);//shift is the index variable of banana class
  }
};

在任何其他类中,我可以调用get_nth_object &传递我想要的指针所在对象的索引号&我会得到那个点。

我的代码有什么问题吗?或者如果有什么可以改进的,请帮助我。

作为参考,我使用http://www.cplusplus.com。我是一名机械工程专业的学生,所以请原谅我,如果我犯了任何愚蠢的错误

直接嵌入是更节省内存的(它节省了指针的开销和堆分配的开销,并提高了引用的局部性):

class banana
{
  private:
  apples ap_obj;
  int index;
}

注意,您在原始代码中忘记了new索引。我甚至不确定我是否理解它的必要性。仅用于查找特定的banana吗?如果是这样,它就不应该是banana的成员。为什么要存储索引呢?引用特定实例的通常方法是使用banana*

首先,banana构造函数本身的语法是不正确的。它不应该被文本类banana {};

包围

其次,使用new在堆上分配内存对于您需要做的事情来说足够快。你不应该以任何其他方式(即不要使用malloc)。所以你在这一点上很好。

对于您的注册表示例,get_nth_object仅在所有banana实例都分配在连续的内存区域....中才能工作当您使用new分配内存时,您无法控制。如果你为你的香蕉指针分配内存使用新的香蕉[size]会更好,内存将是连续的。

即使你让它们在内存中有规律地间隔,如果你需要删除一个香蕉怎么办?还是两三个?还是半打?很快,你将不得不做一些真正紧张的记录来保持工作。

我自己更喜欢在创建香蕉的构造函数中为每个香蕉分配一个唯一的ID,并在香蕉的构造函数中将自己插入到一个关联容器中,如map(即std::map)(在代码中使用#include)。我将使用唯一ID作为键,然后你可以使用指向香蕉的指针作为值。在banana的析构函数中,我会让banana从注册表中删除自己。

您的注册中心将负责拥有关联容器(即映射)。

首先你应该找出你的香蕉->苹果是哪种关系。如果它是一个组合(香蕉是由它的苹果和…组成的),最简单的想法是在香蕉中存储一个苹果实例。

class banana
{
  apple apple_;  // a banana HAS A apple
};

如果这是真的,但是你有无数的香蕉和数量相等的苹果,你可以实现Flyweight模式来安全使用内存。但是你不应该因为你认为你有记忆问题而这样做,而是因为你测量到你因为苹果而有记忆问题。

如果你们的关系更像是一个共享的所有权,你应该在banana中存储一个指向apple实例的指针,并考虑在哪里存储apple对象。最简单的方法是存储std::shared_ptr<apple>,并让引用计数器控制apple的生命周期。

你的第二个问题是如何存储和访问香蕉对象。我将介绍一个BananaRepository,它负责储存和提取香蕉。

class BananaRepository
{
  typedef XYZType BananaID;
  Banana& GetByID(BananaID  id);
  BananaID Add(Banana& b);
};

您应该抽象所使用的ID和存储的类型,这样客户端代码就不依赖于这些细节。每个香蕉都有一个ID,我可以使用这个ID从存储库中获取香蕉。最简单的实现是在bananarerepository中使用banana::ID = vector::size_type和一个vector。

class BananaRepository
{
public:
  typedef std::vector<Banana>::size_type BananaID;
  Banana& GetByID(BananaID  id)
  {
    return bananas_.at(id);
  }
  BananaID Add(Banana& b)
  {
     bananas_.push_back(b);
     return bananas_.size() - 1;
  }
private:
  std::vector<Banana> bananas_;
};

我知道我没有任何运行时错误

嗯,似乎你运行时错误(或更多)。声明

 int *index;

使index成为未初始化的指针,

 *index = ++counter;

counter的内容放在index指向的位置(这可能是完全未定义的)。这肯定会导致奇怪的错误。

也许你想声明

  int index;

 index = ++counter;

我想吗?

  1. 对于存储标量数据,您不需要使用指针。这就是为什么int index

  2. 指定一些"不可能"的值来知道索引是非法的。
  3. 你的方法get_nth_object是错误的。您不能确保所有banana's都分配在一致的内存块中。因此,您不能使用这种线性地址算法来获取对象。查找有关使用动态数组或列表的信息。对于数组,您可能希望检查有关重载订阅操作符

  4. 的信息。