vector::erase()在指向对象的指针向量上执行时,会销毁对象本身吗?

53

我有一个指向对象的指针向量。我需要从向量中删除一个元素,并将该元素放置在另一个列表中。

我了解到可以使用erase来从向量中删除对象,但我也读到它会在执行操作之前调用对象的析构函数。

我需要知道是否擦除对象也会销毁它。


请返回已翻译的文本:相关答案 - fredoverflow
相关:https://dev59.com/ZG855IYBdhLWcg3w-JMr - bwDraco
5个回答

78

vector::erase
从向量容器中删除并调用其析构函数,但如果包含的对象是指针,则不会拥有销毁它的所有权。

您将需要显式调用delete来删除每个包含的指针以删除它所指向的内容,例如:

void clearVectorContents( std::vector <YourClass*> & a ) 
{    
    for ( int i = 0; i < a.size(); i++ ) 
    {       
        delete a[i];    
    }    
    a.clear(); 
} 

在标准容器中存储原始指针并不是一个好主意。如果您真的需要存储必须由new分配的资源,则应使用boost::shared_ptr。请查看Boost文档

更通用和优雅的解决方案:
此解决方案利用了for_eachtemplates,如@Billy在评论中指出:

// Functor for deleting pointers in vector.
template<class T> class DeleteVector
{
    public:
    // Overloaded () operator.
    // This will be called by for_each() function.
    bool operator()(T x) const
    {
        // Delete pointer.
        delete x;
        return true;
    }
};

这可以被称为:

for_each( myclassVector.begin(),myclassVector.end(),
          DeleteVector<myclass*>());

其中,myclassVector 是包含指向 myclass 类对象的指针的向量。

使用示例:

#include "functional"
#include "vector"
#include "algorithm"
#include "iostream"

//Your class
class myclass
{
    public:
        int i;
        myclass():i(10){}
};


// Functor for deleting pointers in vector.
template<class T> class DeleteVector
{
    public:
    // Overloaded () operator.
    // This will be called by for_each() function.
    bool operator()(T x) const
    {
        // Delete pointer.
        delete x;
        return true;
    }
};


int main()
{
    // Add 10 objects to the vector.
    std::vector<myclass*> myclassVector;

    for( int Index = 0; Index < 10; ++Index )
    {
        myclassVector.push_back( new myclass);
    }

    for (int i=0; i<myclassVector.size(); i++) 
    {
        std::cout << " " << (myclassVector[i])->i;
    }

    // Now delete the vector contents in a single  line.
    for_each( myclassVector.begin(),
              myclassVector.end(),
              DeleteVector<myclass*>());

    //Clear the vector 
    myclassVector.clear();

    std::cout<<"\n"<<myclassVector.size();

    return 0;
}

2
那是否意味着如果它是指针向量,析构函数将不会被调用? - cesar
7
+1 是因为表述完整,但如果所包含的对象是指针,则该容器不会拥有销毁它的所有权。 - Nawaz
2
@anonymous 没错。指针本身会被销毁,但程序员需要显式释放它所引用的内存(假设该内存没有被其他地方使用)。 - Dominic Gurto
我测试了你的通用代码... 在 g++ 4.5.2 上并不需要包含 "functional"。 - ashishsony
我认为这很有帮助,因为我不确定存储为vector<string **>的名称-值对向量会发生什么。现在我更加自信地处理C++中OOD的这种看似不透明的情况。 - Jerry Miller
显示剩余5条评论

14
  • 如果你有一个vector<MyObject>,那么MyObject::~MyObject将会被调用。
  • 如果你有一个vector<MyObject*>,那么delete <MyObject instance>将不会被调用。

要在两个向量之间移动MyObject,你需要首先将它插入到目标向量中,然后删除原始向量。请注意,这将创建对象的新副本。当移动指针时,您可以将指针保留在临时变量中,从向量中删除它,然后在需要的位置插入。

这里还有另一种简单的方法来删除并移除向量中的所有项:

template<class T> void purge( std::vector<T> & v ) {
    for ( auto item : v ) delete item;
    v.clear();
}

2

是的,erase会销毁元素。然而,如果您将元素放入另一个容器中,您可能已经复制了它并将其放入该容器中。您可能遇到问题的唯一方式是如果您将指针或类似内容复制到另一个容器中。


是的,我正在使用一个指向对象的指针向量。抱歉,我没有澄清这一点。 - cesar
@anonymous: 啊,那么指针的“析构函数”将被调用。当然,它什么也不做。向量会销毁它实际包含的内容,而不是从中引用的任何内容。(请注意,这意味着您必须返回并手动“删除”它们) - Billy ONeal
哦,好的,为了澄清一下,如果我有: vector<Plane *> p, q; Plane *r = new Plane(); p.push_back(r); q.push_back(r); p.erase(p.begin()); r 和 q.begin() 仍然会引用新创建的 Plane 吗? - cesar
3
如果你只是写了{ Plane * p = new Plane; }, 这个行为和之前相同,当p超出作用域时,它会被“销毁”,但在堆上分配的对象仍然存在。使用裸指针意味着它们是的责任。 - Kerrek SB

1

当然会。如果对象在向量中不存在,它还可能存在哪里呢?

编辑:这不会删除由指针指向的任何内容。您应该使用管理对象生存期的自动生命周期管理指针,例如 shared_ptr


1
是的。vector::erase会销毁被移除的对象,这涉及调用其析构函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接