为什么删除实例矢量替换?

时间:2012-02-29 12:38:20

标签: c++ pointers vector delete-operator

这不是一个实际问题,但它只是为了教育好奇心。

在某些论坛中,我刚刚发现了这段代码:

std::vector<MyClass*> myvec;
for(unsigned int i = 0; i < 100; ++i) {
  myvec.push_back(new MyClass( foo1 ));
}

// somewhere in the code inside a particular if statement
MyClass* replacement = new MyClass( foo2 );
delete myvec[0];
myvec[0] = replacement;

我有一个MyClass实例的向量,代码中的某处我必须用其他实例替换某些实例。

为什么我要拨打删除?更换指针不够吗?

我学到了什么:

7 个答案:

答案 0 :(得分:5)

如果你没有delete原始的MyClass,那么它将保持不变,但是因为你擦掉了它的指针,它将无法访问。那是memory leak

请注意,如果初始分配中的任何new表达式(第一个除外)抛出,那么您将泄漏先前分配的元素。

所有这一切都可以通过不使用vector指针而不是简单的std::vector<MyClass>,或者如果你真的需要使用智能指针来避免。

答案 1 :(得分:2)

您需要明确释放内存,否则它将保持分配状态,但无法访问。这不是Java或C#,垃圾收集器会处理它。

答案 2 :(得分:2)

C ++中最大的问题之一是存储在对象矢量中的类型。

  • 如果对象是可默认构造,可复制和可分配的,则可以存储实例向量,但如果复制和分配很昂贵,那么可以将它们存储在向量中。此外,如果您检索要修改的值,则需要检索引用。但是,如果在您持有此引用时向量发生更改,则您的引用可能会失效

  • 您可以存储指针向量。然后你需要管理指针的生命周期,因为向量不会。

  • 您可以存储shared_ptr的向量,这通常是完成的。它并不理想,因为对象的所有权可能在向量中。你不会遇到麻烦,但这不是处理大量物品的最完美方式。

  • boost为指针提供了一个特殊的向量,可以为您管理生命周期。可以是一个很好的选择

  • 新的C ++ 11将允许可移动对象的向量,我认为也可以允许unique_ptr的向量(auto_ptr的向量不是)。

这是相当主观的,但理想的是将typedef指定为指针类型,然后使用该typedef的向量。如果适合您,您可以稍后更改typedef。 shared_ptr可能会为你完成这项工作。

现在最终结果如下:

typedef spns::shared_ptr< MyClass > MyClassPtr; 
      // spns is an alias to the namespace you use for shared_ptr, either std or boost
std::vector<MyClassPtr> myvec;
for(unsigned int i = 0; i < 100; ++i) 
{
  myvec.push_back(MyClassPtr( new MyClass( foo1 ));
  // but with C++11 if you still use shared_ptr replace with
 // myvec.push_back( spns::make_shared<MyClass>(foo1) );
}

// somewhere in the code inside a particular if statement
MyClass* replacement = new MyClass( foo2 );
myvec[0] = MyClassPtr( replacement );

 // preferred alternative to above 2 lines
 //  myvec[0].reset( new MyClass(foo2) );

答案 3 :(得分:1)

std::vector<MyClass*>是一个指针向量。它不管理它所拥有的对象的生命周期 - 它只管理它所代表的指针数组的内存。

如果您没有正确管理delete,则最终会出现泄漏(除非您最终从另一个错误中删除两次)。

答案 4 :(得分:1)

指针的标准容器永远不会删除它包含的任何指针的目标。它无法知道它们指向使用new创建的对象 - 它们可能是使用new[]创建的(在这种情况下需要delete[]),或者它们可能是指向静态的指针或自动对象,不得删除,或者可能还有其他东西负责删除它们。

通常,您将对象存储在容器中,而不是指针中。如果你真的需要指针(可能是因为对象需要是不同的类型),并且你真的需要这些指针来管理对象的生命周期,可以考虑使用智能指针,例如std::unique_ptr,它会自动删除它的目标,或{ {1}}如果没有。

否则,如果你真的必须使用原始指针来管理对象的生命周期,那么你必须小心谨慎地在适当的时候使用boost::ptr_vector。在这种情况下,诸如Valgrind之类的工具可以帮助识别不可避免的内存泄漏。

答案 5 :(得分:1)

致电时

new MyClass( foo1 )

内存在堆中分配,用于存储类MyClass的对象。 此记忆保持分配状态,直到您使用删除自己释放它。

因此,对于每次调用new,您应该在代码中的某处删除相应的调用。

答案 6 :(得分:0)

在你的vector中,你存储了指针,指向你自己的内存。如果你刚刚替换了vector的一个元素,那么该向量对该内存没有任何作用,也许某些类会自动释放该内存,但vector不会这样做。我认为你可以在正常数组中考虑相同的条件而不是向量。