2008-12-20 45 views

回答

18

指针的STL容器不会清理指向的数据。它只会清理指针的空间。如果你想在矢量清理指针数据,你需要使用某种类型的智能指针实现的:在该范围两端载体将释放其内部阵列

{ 
    std::vector<SomeClass*> v1; 
    v1.push_back(new SomeClass()); 

    std::vector<boost::shared_ptr<SomeClass> > v2; 
    boost::shared_ptr<SomeClass> obj(new SomeClass); 
    v2.push_back(obj); 
} 

。v1会泄漏创建的SomeClass,因为只有它的指针位于数组中。 v2不会泄露任何数据。

0

如同在堆中的任何其他对象,它必须被手动破坏(与删除)。

2

当一个向量超出作用域时,编译器向其析构函数发出一个调用,然后释放堆中分配的内存。

2

这有点误用。与大多数STL容器一样,矢量由2个逻辑部分组成。

  1. 载体实例
  2. 实际的底层数组实现

虽然配置,#2几乎总是住在堆上。然而#1可以在堆栈或堆上生存,这取决于它是如何分配的。例如

void foo() { 
    vector<int> v; 
    v.push_back(42); 
} 

在这种情况下,零件#1住在堆栈上。

现在#2如何被破坏?当矢量的第一部分被破坏时,它也会破坏第二部分。这是通过删除矢量类的析构函数内的底层数组来完成的。

0

要回答你的第一个问题:

有什么特别的STL类(我希望)。它们的功能与其他模板类完全相同。因此,如果在堆上分配它们,它们不会自动销毁,因为C++没有对它们进行垃圾回收(除非您告诉它带有某些花哨的autoptr业务或其他东西)。如果你在堆栈上分配它(没有新的),它很可能会被C++自动管理。

关于第二个问题,这里有一个非常简单的ArrayOfTen类,以演示用C典型的内存管理的基本知识++:

/* Holds ten Objects. */ 
class ArrayOfTen { 
    public: 
     ArrayOfTen() { 
      m_data = new Object[10]; 
     } 

     ~ArrayOfTen() { 
      delete[] m_data; 
     } 

     Object &operator[](int index) { 
      /* TODO Range checking */ 
      return m_data[index]; 
     } 

    private: 
     Object *m_data; 

     ArrayOfTen &operator=(const ArrayOfTen &) { } 
}; 

ArrayOfTen myArray; 
myArray[0] = Object("hello world"); // bleh 

基本上,ArrayOfTen类不断堆10种对象元素的内部数组。当在构造函数中调用new []时,十个对象的空间被分配到堆上,十个对象被构造。同样,当在析构函数中调用delete []时,十个对象被解构,然后释放先前分配的内存。

对于大多数(所有?)STL类型,调整大小是在幕后完成的,以确保有足够的内存设置来满足您的元素。上面的类只支持10个对象的数组。它基本上是Object的一个非常有限的typedef [10]。

5

如果你有vector<T*>,你的代码需要在删除vector之前删除这些指针:否则,这个内存会被泄漏。

要知道,C++没有做垃圾收集,这里是为什么(appologies的语法错误,它已经有一段时间我写C++)为例:

typedef vector<T*> vt; 
⋮ 
vt *vt1 = new vt, *vt2 = new vt; 
T* t = new T; 
vt1.push_back(t); 
vt2.push_back(t); 
⋮ 
delete vt1; 

最后一行(显然不应该删除它包含的指针;毕竟,它也在vt2中。所以它没有。并且也不会删除vt2

(如果您希望删除的破坏指针,矢量型这种类型当然也可以写。也许一直。但要注意执行删除操作的指针,别人仍持有的副本。)

+1

是的它有:boost :: ptr_vector。 (请参阅boost ptr容器) – 2008-12-21 03:51:04

2

如果您将指针存储在STL容器类中,则需要在对象被销毁之前手动删除它们。这可以通过遍历整个容器并删除每个项目或使用某种智能指针类来完成。但是不要使用auto_ptr,因为它根本不适用于容器。

这样做的一个好的副作用是您可以在程序中保留多个指针容器,但只有那些容器拥有这些对象,并且您只需清理那个容器。

删除的指针是做最简单的方法:使用升压转换器的ptr_vector

for (ContainerType::iterator it(container.begin()); it != container.end(); ++it) 
{ 
    delete (*it); 
} 
+0

这不是可取的(除非部分析构函数),因为它不是异常安全的。你应该使用一个容器,它理解那个拿着一个指针。 – 2008-12-21 03:49:25

0

要删除的元素指着我写了一个简单的仿函数:

template<typename T> 
struct Delete { 
    void operator()(T* p) const { delete p; } 
}; 

std::vector<MyType> v; 
// .... 
std::for_each(v.begin(), v.end(), Delete<MyType>()); 

但是,你应该回退在向量的内容将被...共享时共享指针。是。

0

标准STL容器放置原始对象的副本放入容器中,使用复制构造函数。当容器被销毁时,容器中每个对象的析构函数也被调用来安全地销毁对象。

指针的处理方式相同。
事情是指针是POD数据。指针的复制构造函数只是复制地址,POD数据没有析构函数。如果你想容器管理一个指针,你需要:

  • 使用智能指针的容器。 (如共享指针)。
  • 使用boost ptr容器。

我更喜欢指针容器:
指针的容器是一样的,除非你的STL容器把指针放进去,但随后的容器拍摄对象的所有权指针所指向的,因而会回收对象(通常通过调用delete)当容器被销毁时。

访问ptr容器的成员时,它们通过引用返回,因此它们的行为与标准算法中使用的标准容器类似。

int main() 
{ 
    boost::ptr_vector<int> data; 

    data.push_back(new int(5)); 
    data.push_back(new int(6)); 

    std::cout << data[0] << "\n"; // Prints 5. 
    std::cout << data[1] << "\n"; // Prints 6. 


} // data deallocated. 
    // This will also de-allocate all pointers that it contains. 
    // by calling delete on the pointers. Therefore this will not leak. 

人们还应该指出的是,在一个容器智能指针是一个有效的替代方案,不幸的std :: auto_ptr的<>是不是这个情况智能指针的有效选择。

这是因为STL容器假定它们包含的对象是可复制的,不幸的是std :: auto_ptr <>不能以传统意义复制,因为它破坏了复制的原始值,因此复制源不能是const。

0

STL容器就像任何其他对象,如果你实例化一个它是在栈上创建:

std::vector<int> vec(10); 

就像任何其他的堆栈变量,它只是生活在它被定义的函数的范围,并且不需要手动删除。 STL容器的析构函数将调用容器中所有元素的析构函数。

保持容器中的指针是一个冒险的问题。既然指针没有析构函数,我会说你永远不会想把原指针放到STL容器中。以异常安全的方式进行此操作将非常困难,您必须使用try {} finally {}块清理代码,以确保包含的指针总是被释放。

那么你应该放入容器而不是原始指针? +1 jmucchiello提升boost :: shared_ptr。 boost :: shared_ptr在STL容器中使用是安全的(与std :: auto_ptr不同)。它使用简单的引用计数机制,并且可以安全地用于不包含循环的数据结构。

包含循环的数据结构需要什么?在这种情况下,您可能想要毕业于垃圾收集,这实际上意味着使用不同的Java语言。但那是另一个讨论。 ;)