简体   繁体   English

为什么我需要手动删除vector中的指针?

[英]Why do I need to delete pointers from vector manually?

Why do I need to delete dynamically created items in vector, manually? 为什么我需要手动删除向量中动态创建的项目? Why wouldn't they get deleted or its destructor called when vector got deleted? 当向量被删除时,为什么它们不会被删除或者它的析构函数被调用?

Normally something like this, but why needed ? 通常是这样的,但为什么需要?

vector<int*> v;
for (vector<int*>::iterator it = v.begin(); it != v.end(); ++it) 
{ 
   delete *it; 
}

Firstly, you store raw pointers in your vector. 首先,将原始指针存储在向量中。 These pointers are just pointers. 这些指针只是指针。 They can point anywhere. 他们可以指向任何地方 They can point to local objects, which cannot be deleted by delete . 它们可以指向本地对象,这些对象无法通过删除delete And even if they point to dynamically created objects, it doesn't necessarily mean that the user wants them to die with the vector. 即使它们指向动态创建的对象,也不一定意味着用户希望它们与向量一起死亡。 How is the vector supposed to know all this? 矢量如何知道这一切?

It is a matter of object ownership. 这是对象所有权的问题。 Whoever owns the object is responsible for its proper and timely deletion. 拥有该对象的人有责任及时删除。 Ordinary raw pointers do not express ownership. 普通原始指针不表示所有权。 That is why vector can't make any assumptions about whether the objects need to be deleted or not. 这就是为什么vector无法对是否需要删除对象做出任何假设。 If you want to tell the vector that it owns its dynamic objects, use corresponding smart pointers. 如果要告诉向量它拥有动态对象,请使用相应的智能指针。

Secondly, note that your deletion technique is not necessarily safe in the general case. 其次,请注意您的删除技术在一般情况下不一定安全。 Some standard containers assume that the data you store in them is always valid. 某些标准容器假定您存储在其中的数据始终有效。 When you do delete on each vector element, the data in the vector becomes "invalidated" (pointers become indeterminate). 当您对每个向量元素执行delete ,向量中的数据将变为“无效”(指针变为不确定)。 This is OK with a vector. 这对矢量来说没问题。 But doing something like this in a "smarter" container, like std::map or std::unordered_set for example, can and will lead to problems. 但是在“更聪明”的容器中做这样的事情,例如std::mapstd::unordered_set ,会导致问题。 Even if you destroy the container itself immediately afterwards, it is perfectly possible that the container's destruction algorithm might need to analyze (compare, hash etc.) the values of individual elements. 即使您之后立即销毁容器本身,容器的销毁算法也可能需要分析(比较,散列等)各个元素的值。 And you just killed them all with your cycle. 而你刚刚用你的周期杀死它们。

Smart pointers naturally resolve this matter. 智能指针自然会解决这个问题。 But if you have to use a manual delete for raw pointers stored in a standard container, a better sequence of steps would be this 但是,如果必须对存储在标准容器中的原始指针使用手动delete ,则可以采用更好的步骤顺序

  1. Retrieve the value of the element at i and store it in pointer p i处检索元素的值并将其存储在指针p
  2. Erase the element at i from the container 从容器中删除i处的元素
  3. Do delete p delete p

In the end you end up with an empty container and delete d data. 最后,您最终得到一个空容器并delete d数据。 Again, your approach will work for simple sequences, like std::vector or std::list , but don't do this with ordered or hashed ones. 同样,您的方法将适用于简单的序列,如std::vectorstd::list ,但不要使用有序或散列的序列。

Because the language has no way of knowing whether you need them to remain alive when you're done. 因为当你完成时,语言无法知道你是否需要它们保持活力。 What if you inserted some pointers to stack objects or something like that? 如果你插入一些指向堆栈对象或类似的东西怎么办? Boom. 繁荣。

This, however, can be remedied by using a smart pointer, which will implement an appropriate policy as to automatic destruction. 但是,这可以通过使用智能指针来解决,智能指针实现适当的自动销毁策略。 unique_ptr and shared_ptr are the most common and useful. unique_ptrshared_ptr是最常用和最有用的。

The destructor is not called because the pointer does not own the object to which it points. 不会调用析构函数,因为指针不拥有它指向的对象。

In C++11, a std::unique_ptr<T> does indeed own the object to which it points. 在C ++ 11中, std::unique_ptr<T>确实拥有它指向的对象。 In this case, the destructor is called when the pointer is released, which is probably the behavior you want. 在这种情况下,释放指针时会调用析构函数,这可能是您想要的行为。 (If you don't have a C++11 compiler but have a reasonably recent pre-C++11 compiler, unique_ptr is still available as part of TR1.) (如果你没有C ++ 11编译器但是有一个合理的最新的C ++ 11之前的编译器,那么unique_ptr仍然是TR1的一部分。)

The implementation of vector was just made to delete its memory only. vector的实现只是为了删除它的内存。 Pointers do not have deconstructors. 指针没有解构器。 And in C++, there is no garbage collection or logic to see that it is pointers and recursive delete it. 在C ++中,没有垃圾收集或逻辑可以看到它是指针并且递归删除它。

If you would like to attend the next ISO meeting and propose that, be my guest, but for me, I just put it in an inline function: 如果您想参加下一次ISO会议并提出建议,请成为我的客人,但对我而言,我只是将其置于inline函数中:

template<class T>
public static inline void deleteVectorPointer(std::vector<T*> v)
{
    for (vector<T*>::iterator i = v.begin(); i != v.end(); i++)
    {
        delete *i;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM