如何动态地从向量中删除指向c ++中对象的指针?

时间:2014-01-15 07:16:02

标签: c++ pointers dynamic vector element

好的,所以我正在做这个游戏就像一个项目,我有3个不同的对象。

void Character::shoot(){
  Shot* s = new Shot(blablabla);
  shots.push_back(s);
}

这是动态发生的,目前我不删除指针所以它必须在一段时间后加载指向该向量中的镜头的指针。

我使用Bot,Character和Shot,正如我所说,我需要帮助存储和移动指向动态的指针,最好是从矢量。我已经让它像我将所有镜头对象放在矢量中一样工作,但它们永远不会从那里消失。我想在程序碰撞时将其永久地从我的程序中删除,或者到达屏幕宽度之外。

3 个答案:

答案 0 :(得分:1)

使用简单的矢量方法

您可以通过std::vector进行迭代并使用erase()方法删除当前的镜头:

std::vector<cls*> shots; // Your vector of shots
std::vector<cls*>::iterator current_shot = shots.begin(); // Your shot to be deleted

while( current_shot < shots.end()){
    if((*current_shot)->needs_to_be_deleted()){
        // Remove item from vector
        delete *current_shot;
        current_shot = shots.erase(current_shot);
    } else {
        (*current_shot)->draw();
         ++current_shot; // Iterate trough vector
    }
}

erase()在删除元素后将迭代器返回到下一个元素,因此使用了while循环。

<小时/>

将值设置为null并调用std::remove()

请注意,std::vector::erase()会在删除项目后重新组织所有内容:

  

因为矢量使用数组作为其底层存储,所以擦除   在矢量端以外的位置的元素导致容器   将段删除后的所有元素重新定位到新的元素   位置。与此相比,这通常是低效的操作   一个由其他类型的序列执行相同的操作   容器(例如list或forward_list)。

这样您最终可能会有O(n^2)的复杂性,因此您可能会将值设置为null并使用{juanchopanza在评论std::remove()中建议的Erase-Remove idiom 功能

int deleted = 0;
for( current_shot = shots.begin(); current_shot < shots.end(); ++current_shot){
    if((*current_shot)->needs_to_be_deleted()){
        // Remove item from vector
        delete *current_shot;
        *current_shot = null;
        ++deleted;
    }
}

if( deleted){
    shots.erase( std::remove(shots.begin(), shots.end(), null));
}

<小时/>

使用std::list

如果您需要大量数量的镜头创建和删除std::vector可能不是包含此类列表的最佳结构(特别是当您想要从中间删除项目时):

  

在内部,向量使用动态分配的数组来存储它们   元素。此阵列可能需要重新分配才能增长   插入新元素时的大小,这意味着分配一个新元素   数组并将所有元素移动到它。这是相对昂贵的   在处理时间方面的任务,因此,矢量不重新分配   每次将一个元素添加到容器中。

请参阅link from Raxvan's comment进行效果比较。

您可能希望改为使用std::list

  

列表容器实现为双向链表;双重联系   列表可以存储它们包含在不同和中的每个元素   不相关的存储位置。订购由协会保存   到它前面的元素的链接的每个元素和链接到   跟随它的元素。

     

与其他基本标准序列容器(array,vector和   deque),列表在插入,提取和执行方面表现得更好   移动元件在容器内的任何位置   迭代器已经获得,因此也在算法中   大量使用这些,如排序算法。

     

list和forward_lists的主要缺点是与其他这些相比   序列容器是他们缺乏对元素的直接访问   他们的立场;

这对于从“数组”中间删除项目非常有用。

至于删除,请使用deletestd::list::erase()

std::list<cls*> shots;
std::list<cls*>::iterator current_shot;

// You have to use iterators, not direct access
for( current_shot = shots.begin();  current_shot != shots.end(); current_shot++){
    if( (*current_shots)->needs_to_be_deleted()){
        delete *current_shot;
        shots.erase(current_shot); // Remove element from list
    } 
}

<小时/>

使用std::shared_ptr

如果您有更复杂的程序结构,并且您在许多地方使用相同的对象,您可以简单地确定是否可以删除对象,或者您需要将它保持活动多一点(如果您使用的是C + +11),您可以使用std::shared_ptr(或使用不同类型的“智能指针”删除引用计数达到零的数据):

// Pushing items will have slightly more complicated syntax
std::list< std::shared_ptr<cls>> shots;
shots.push_back( std::shared_ptr( new cls()));
std::list< std::shared_ptr<cls>>::iterator current_shot;

// But you may skip using delete
shots.erase(current_shot); // shared_ptr will take care of freeing the memory

答案 1 :(得分:1)

您可以在任何标准容器上使用std::removestd::erase来删除内容:

Shot* to_be_removed = ...;
std::vector<Shot*>::iterator i = std::remove(shots.begin(),shots.end(),to_be_removed);
std::erase(i,shots.end());
delete (to_be_removed);//don't forget to delete the pointer

当您知道要删除的元素时,此方法有效。如果您不知道该元素,则必须找到一种方法来识别要删除的元素。此外,如果您有一个系统来识别元素,则可以更容易地使用容器迭代器来执行删除:

std::vector<Shot*>::iterator i = ...;//iterator the the element you want to remove
delete (*i);//delete memory
shots.erase(i);//remove it from vector

最后,如果你想从容器中删除所有指针并同时删除所有项目,你可以使用std::for_each

//c++ 03 standard:
void functor(Shot* s)
{
    delete(s);
}

std::for_each(shots.begin(),shots.end(),functor);
shots.clear();//empty the list

//or c++11 standard:
std::for_each(shots.begin(),shots.end(),[] (Shot * s){ delete(s); } );
//the rest is the same

答案 2 :(得分:0)

只需使用&#34;删除&#34;释放记忆:

vector<Shot*>::iterator i;
for(i = shoot.begin(); i != shoot.end(); ++i)
{
    delete (*i);//delete data that was pointed
    *i = 0;
}
shoot.clear();

这将删除堆中的所有元素并清除矢量。