【问题标题】:How would I store multiple instance objects correctly?如何正确存储多个实例对象?
【发布时间】:2013-01-09 06:33:59
【问题描述】:

我正在制作一个中级/高级 C++ 程序,确切地说是一个视频游戏。

最近我注意到有大量内存泄漏,我想知道我创建实例的方式是否有问题。

下面是一个总结(但最初很复杂)的类:

class theObject
{
 //Instance variables
 //Instance functions
};

有了这个对象(连同我存储的任何其他对象,我有一个theObject 的每个不同变体模板的数组索引。这部分并不重要,但我存储它们的方式(或在我看来) 是:

//NEWER VERSION WITH MORE INFO
void spawnTheObject()
{
 theObject* NewObj=ObjectArray[N];
 //I give the specific copy its individual parameters(such as its spawn location and few edited stats)
 NewObj->giveCustomStats(int,int,int,int);//hard-coded, not actual params
 NewObj->Spawn(float,float,float);
 myStorage.push_back(new theObject(*NewObj));
}


//OLDER VERSION
void spawnTheObject()
    {
     //create a copy of the arrayed object
     theObject* NewObj=new theObject(*ObjectArray[N]);
     //spawn the object(in this case it could be a monster), and I am spawning multiple copies of them obviously
     //then store into the storage object(currently a deque(originally a vector))
     myStorage.push_back(new theObject(*NewObj));
     //and delete the temporary one
     delete NewObj;
    }

我目前正在使用双端队列(最近从使用向量更改),但我发现内存使用量没有差异。我虽然从“评论测试”中发现,我拥有的这些生成功能是内存泄漏的原因。由于这是创建/生成实例的错误方法,我想知道是否有更好的方法来存储这些对象。

tl;dr:有哪些更好的对象来存储非常量的对象以及如何存储?

【问题讨论】:

  • 使用智能指针,忘记内存泄漏。
  • "当你需要一个(非平凡的)复制构造函数、复制赋值运算符或析构函数时,你很可能也需要实现其他的"
  • @9dan 指的是the rule of three

标签: c++ storage instance


【解决方案1】:

我猜你永远不会清除myStorage 中的新生成对象,这会导致内存增加(正如你所说的内存泄漏)。如果我是正确的,您的 myStorage 声明如下:

std::deque<theObject*> myStorage;

如果您调用以下任一调用,指向对象的指针将被删除,但不会删除真正动态分配的对象。

 myStorage.pop_back();
 myStorage.clear();

您的代码中的另一个小问题是,您在 spawnTheObject() 函数中进行了不必要的对象分配/删除。

如何清理指针类型的容器

你需要遍历myStorage中的每个元素,删除对象然后清空容器,例如:

for (std::deque<theObject*>::iterator iter=myStorage.begin();
     iter != myStorage.end(); ++iter)
{
   delete (*iter);
}
myStorage.clear();

更好的解决方案:

std::dequestd::vector 中使用智能指针,然后当您从STL 容器中删除一个元素时,该指针指向的对象也会被自动删除。

 #include <memory>

 std::deque<std::shared_ptr<theObject> > myStorage;
 myStorage.push_back(std::shared_ptr<theObject>(new *ObjectArray[N]));

 mySorage.clear();  // all memories cleared properly, no worries

【讨论】:

  • 好吧,我真的不明白为什么我总是收到错误:shared_ptr is not a member of std。我为项目添加了内存,甚至将其添加到了单个文件中。
  • 好吧,我发现因为我使用的是 Gcc,所以我必须使用&lt;tr1/memory&gt;
  • 是的,如果您的 gcc 不是最新版本。 shared_ptr 在 tr1(技术报告 1)下。它也在 std::tr1 命名空间下。
  • spawnTheObject,哪个分配/解除分配是不必要的?我要做的是获取阵列模板“怪物”的副本并将其生成到其位置,同时将其记录在双端队列中。我将更新我的问题以显示我现在所做的更改。
  • 那你建议我用什么来生成对象?
【解决方案2】:

如果您在游戏结束或需要销毁它们时没有从myStorage 手动删除您的对象,则存在内存泄漏。

myStorage.push_back(new theObject(*NewObj));

被推入存储的对象是你分配的,所以当它需要消失时应该由你销毁。

我也不明白中间 NewObj 对象的必要性,这不是内存泄漏,而是不必要的性能成本,1 次分配/解除分配 + 1 次复制。

正如 Forever 所说,最好的办法是开始使用智能指针,std::unique_ptrstd::shared_ptr(仅适用于 c++11)。

【讨论】:

  • 等等,我应该只使用shared_ptr 作为双端队列吗?还是针对我创建的每个实例?
  • 双端队列的类型应该是std::deque&lt;std::shared_ptr&lt;theObject&gt; &gt;
  • 为什么不是deque&lt;theObject&gt;?从他的代码示例中可以明显看出,@Molma 很乐意复制 theObject 实例并且不需要多态克隆,因此动态分配和智能指针是不必要的复杂化。
  • @CharlesBailey 取决于是否编写其余代码以将双端队列视为代码的所有者。如果是这样,那么您是对的,按价值存储就足够了。但是,代码的某些部分(例如排序)可能会影响性能。
  • @CharlesBailey 实际上,deque&lt;theObhect&gt; 是我在存储非恒定数量的对象时唯一能想到的......是的,我想确保我不会造成大量内存泄漏,但我仍然想确保我也会复制必要数量的“怪物”。我真正需要的是一种复制然后删除“怪物”的方法,以便释放内存。怪物可以在需要时重新制作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多