简体   繁体   English

指向向量元素的C ++指针,元素已删除

[英]C++ pointer to vector element, element erased

Simple question I hope.. 我希望一个简单的问题..

I have a vector of elements. 我有元素向量。 The elements are of my own class type. 元素是我自己的类类型。 I maintain a pointer to a particular member of that vector. 我维护了指向该向量的特定成员的指针。

Question is: If I remove the element from the vector, what happens to the pointer? 问题是: 如果我从向量中删除元素,指针将如何处理?

Sub-questions : 子问题

  • When iterating through the vector, is there any way I can check to see if the iterator is pointing to the element to which I currently have the pointer? 遍历向量时,有什么方法可以检查迭代器是否指向我当前具有指针的元素? Would vIterator == pElement do it? vIterator == pElement会这样做吗?
  • Is there any way of erasing the element from the vector, with only a pointer to that element? 有什么方法可以仅通过指向该元素的指针来擦除向量中的元素? If the answer to the previous question is yes, then I guess I can do it with a loop. 如果对上一个问题的答案是肯定的,那么我想我可以循环进行。

Thanks in advance! 提前致谢!

  1. It will now point to invalid memory a or to a different object. 现在它将指向无效的内存a或其他对象。 In general, using that pointer is now undefined behavior. 通常,使用该指针现在是未定义的行为。
  2.  if(&*vIterator == ptr) ... 

    Where * gets a reference to the object from the iterator, & gives you its address. *从迭代器获取对该对象的引用, &为您提供其地址。 Notice that, although &* is a no-op on pointers, here we need it because iterators overload * . 请注意,尽管&*是禁止操作的指针,但是在这里我们需要它,因为迭代器会重载*

  3. You can do with a linear search, but it's needlessly inefficient. 您可以使用线性搜索来完成,但这是不必要的效率低下。 You can take advantage from the fact that storage is contiguous, and do: 您可以从存储是连续的这一事实中获益,并执行以下操作:

     vec.erase(vec.begin()+(ptr-&vec[0])); 

    ptr-&vec[0] gives you the index in the vector due to usual pointer arithmetic, and adding it to the begin iterator results in an iterator to it. ptr-&vec[0]由于通常的指针算法而为您提供了向量中的索引,并将其添加到begin迭代器中将导致对其进行迭代。


a. 一种。 Technically the vector isn't allowed to deallocate memory on element removal, so it may be more correct to say that it may point to an invalid (=already destroyed) object. 从技术上讲,向量不允许在元素删除时释放内存,因此说它可能指向无效(已销毁)的对象可能更正确。

Pointer to removed object 指向已删除对象的指针

That highly depends on how actually do you store the classes in the vector. 这很大程度上取决于您实际上如何将类存储在向量中。 Let's suppose, that you're doing it in the following way: 假设您是以以下方式进行操作:

std::vector<MyClass> classes;

If you look into std::vector 's constructor, you'll see, that it takes also another parameter, the allocator. 如果看一下std::vector的构造函数,您会发现它也采用了另一个参数,即分配器。 This is because vector is responsible for taking care of allocating and deallocating memory for items, which it holds. 这是因为vector负责照顾它持有的项目的内存分配。

In case if you use the mentioned notation, the vector allocates memory each time you add item to it and deallocates, when you remove. 如果使用上述表示法,则向量每次向其添加项目时都会分配内存,而在删除时会取消分配。 So if you keep a pointer to some element in the vector and remove it, the pointer will then point to invalid memory (to deallocated object) and you should not use it anymore. 因此,如果在向量中保留指向某个元素的指针并将其删除,则该指针将指向无效内存(指向已释放的对象),因此您不应再使用它。

Situation changes, if you keep objects in the following way: 如果您通过以下方式保留对象,情况将发生变化:

std::vector<MyClass *> classes;

In such case, vector is responsible only for keeping pointers to classes and will allocate and deallocate pointers (not thinking about what do they point to). 在这种情况下,向量仅负责保持指向类的指针 ,并将分配和取消分配指针 (不考虑它们指向的内容)。 You are then responsible for creating and destroying elements pointed to pointers kept in the vector. 然后,您负责创建和销毁指向向量中保留的指针的元素。

Iterating 迭代

There is a simple way to check, whether iterator points to specific object. 有一种简单的方法可以检查迭代器是否指向特定对象。 First, dereference the iterator to get the actual object: (*iter) Then ask for address of that object: &(*iter) and check, if it matches object you have a pointer to. 首先,取消对迭代器的引用以获取实际的对象: (*iter)然后询问该对象的地址: &(*iter)并检查它是否与您具有指针的对象匹配。

Erasing 删除

Yes, you can - simply using the loop, for instance. 是的,您可以-例如,仅使用循环即可。 The option Matteo suggested will work if you keep the actual objects in the vector (the first option I mentioned). 如果将实际对象保留在矢量中,则Matteo建议的选项将起作用(我提到的第一个选项)。 This is because vector is supposed to keep all its data in a continuous block of memory and it is easy to evaluate the index of the object, when you have a pointer to it (pointer arithmetics). 这是因为应该将向量的所有数据保存在连续的内存块中,并且当您拥有指向它的指针(指针算术)时,很容易评估对象的索引。

Your vector owns the objects but you also want to be able to delete them using their pointers. 向量拥有对象,但您还希望能够使用其指针将其删除。 You can't achieve this clearly if you store them directly in the vector since as you suspected the vector may do a reallocation when changing it's size and an insertion or deletion in the middle of the vectors will invalidate all pointers that point to the next elements. 如果直接将它们存储在向量中,则无法清楚地实现这一点,因为您怀疑向量在更改其大小时可能会重新分配,并且向量中间的插入或删除将使所有指向下一个元素的指针无效。

This is where std::unique_ptr comes into play. 这就是std :: unique_ptr起作用的地方。 By keeping smart pointers in your vector, you still retain ownership without having to deal with memory management and invalidation is not a problem: 通过将智能指针保留在向量中,您仍然可以保留所有权,而不必处理内存管理,并且无效不是问题:

std::vector<std::unique_ptr<CustomClass>> objects;
std::unique_ptr<CustomClass> object(new CustomClass());
objects.push_back(std::move(object));

Now assuming that object_pointer has the address of one of your objects you can remove that object without worrying about invalidation: 现在假设object_pointer具有对象之一的地址,则可以删除该对象而不必担心失效:

objects.erase(
     std::remove_if(objects.begin(), m_objects.end(),
        [&](const std::unique_ptr<CustomClass>& ptr) { return ptr.get() == object_pointer; }),
     objects.end()
);

Question If I remove the element from the vector, what happens to the pointer? 问题如果我从向量中删除元素,指针将如何处理?

Answer 回答

Here's the documentation on std::vector:erase 这是std::vector:erase上的文档

Erase elements 擦除元素

Removes from the vector either a single element ( position ) or a range of elements ( [first,last) ). vector移除单个元素( position )或一系列元素( [first,last) )。

This effectively reduces the container size by the number of elements removed, which are destroyed. 这有效地减少了容器尺寸,减少了被破坏的元素的数量。

Because vector s use an array as their underlying storage, erasing elements in positions other than the vector end causes the container to relocate all the elements after the segment erased to their new positions. 由于vector使用数组作为其基础存储,因此在除vector端以外的其他位置擦除元素会导致容器在将段擦除到其新位置后重新定位所有元素。 This is generally an inefficient operation compared to the one performed for the same operation by other kinds of sequence containers (such as list or forward_list ). 与其他类型的序列容器(例如listforward_list )对同一操作执行的操作相比,这通常是一种低效的操作。

It isn't clear to me whether the elements are required to be relocated to the existing memory or a compiler is free to allocate new memory for the elements and relocate the elements to the new memory, then delete the old memory. 我不清楚是否需要将元素重定位到现有内存,还是编译器可以自由地为元素分配新内存,然后将元素重定位到新内存,然后删除旧内存。

Best case scenario is the elements are relocated to existing memory. 最好的情况是将元素重定位到现有内存。 Even then... 即使这样...

If you have a pointer to the n-th element of the vector before elements were erased from it and the size of the vector is less than n after elements have been erased, you are holding on to a dangling pointer. 如果你有一个指针的第n个元素vector之前元素被从它擦除和的大小vector小于n元件被擦除之后,如果持有到悬空指针。 If you access the pointer, you are likely to get undefined behavior. 如果访问指针,则可能会得到未定义的行为。 If number of elements in the vector is greater or equal to n , you are pointing to a new object but it is still a valid object. 如果vector的元素数大于或等于n ,则您指向的是新对象,但它仍然是有效对象。

Question When iterating through the vector, is there any way I can check to see if the iterator is pointing to the element to which I currently have the pointer? 问题在遍历向量时,有什么方法可以检查迭代器是否指向我当前具有指针的元素? Would vIterator == pElement do it? vIterator == pElement会这样做吗?

Answer You can check whether you have the address of an element using: 答案您可以检查是否有使用元素的地址:

if ( myptr == &(*iter) ) 如果(myptr ==&(* iter))

Question Is there any way of erasing the element from the vector, with only a pointer to that element? 问题是否有任何方法可以仅通过指向该元素的指针来擦除向量中的元素?

Answer Since the answer to the previous question is "Yes", the answer to this question is also "yes". 答案由于上一个问题的答案为“是”,因此该问题的答案也为“是”。

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

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