将元素添加到抽象类的std :: vector中

时间:2015-07-14 15:25:14

标签: c++ vector

我想在一个抽象类的std :: vector中存储从公共接口(抽象类)派生的类的对象。这个向量应该填充一个循环,通常我会调用一个类的构造函数并将创建的对象推送到向量中。

据我所知,在抽象类的情况下,我只能存储指向该类的指针,所以我需要push_back派生类的指针。但是,我不确定这些新创建的对象的范围。

请看下面的代码。此代码编译并正常工作,但我的问题是:

a)对象是否保证存在于main函数的第二个for-loop中?或者他们是否可以在创建它们的循环范围之外停止存在?

b)是否所有物品都是'调用析构函数或可能存在内存泄漏?

#include<vector>
#include<iostream>
class Interface {
    public:
    Interface( int y ) : x(y) {}
    virtual ~Interface() {}
    virtual void f() = 0;
    int x;  
};

class Derived_A : public Interface {
    public:
    Derived_A( int y ) : Interface(y) {}
    void f(){ return; }
};

class Derived_B : public Interface {
    public:
    Derived_B( int y ) : Interface(y) {}
    void f(){ return; }
};


int main()
{
    std::vector<Interface*> abstractObjects;
    int N = 5;
    for(int ii = 0; ii < N; ii++ )
    {
        abstractObjects.push_back( new Derived_A(ii) );
        abstractObjects.push_back( new Derived_B(ii) );
    }

    for(int ii = 0; ii < abstractObjects.size(); ii++ )
    {
        abstractObjects[ii]->f();
        std::cout << abstractObjects[ii]->x << '\t' << std::endl;
    }


    for(int ii = 0; ii < abstractObjects.size(); ii++ )
    {
        delete abstractObjects[ii];
    }

    return 0;
}

4 个答案:

答案 0 :(得分:9)

这是智能指针的完美案例。您可以将指针存储在RAI类型的unique_ptr中。当unique_ptr超出范围时,它会自动为您删除内存。

    //...
    std::vector<std::unique_ptr<Interface>> abstractObjects;
    int N = 5;
    for(int ii = 0; ii < N; ii++ )
    {
        abstractObjects.push_back( std::make_unique<Derived_A>(ii) );
        abstractObjects.push_back( std::make_unique<Derived_B>(ii) );
    }

    for(auto & e : abstractObjects)  // ranged based for loop
    {
        e->f();
        std::cout << e->x << '\t' << std::endl;
    }
    // no need to do anything here.  the vector will get rid of each unique_ptr and each unique_ptr will delete each pointer
    return 0;
}

答案 1 :(得分:4)

让我谈谈你的观点。

  

a)对象是否保证存在于第二个for循环中   主功能?或者他们可能会停止超出范围的存在   它们被创建的循环?

当您调用关键字new时,对象将一直存在,直到您明确调用delete来释放相关内存。如果您在堆栈上创建了对象,则在第一个循环终止后它们将超出范围。

  

b)是否所有对象的析构函数都被调用或存在内存泄漏?

是的,您正在调用最终循环中每个对象的析构函数,并且通常不会出现内存泄漏。但是,如果在到达最终循环之前抛出异常,则不会回收分配的内存,并且发生泄漏。请参阅this post

但是,您可以通过使用智能指针来改进代码,智能指针可以通过自动回收内存来解决问题。使用std::make_unique<Derived_A>(ii)而不是new Derived_A(ii),当向量超出范围时,它将自动为其包含的每个对象释放相关内存,从而无需在最终循环中自己显式调用析构函数。

答案 2 :(得分:2)

是的,对象仍存在于您的第一个for循环范围之外,因此您对delete他们是正确的。

不会自动调用所有对象的析构函数。如果您new某事,那么您必须delete。但是你可以(而且应该)使用智能指针。

std::vector<std::unique_ptr<Interface>> abstractObjects;
int N = 5;
for(int ii = 0; ii < N; ii++ )
{
    abstractObjects.push_back( std::make_unique<Derived_A>(ii) );
    abstractObjects.push_back( std::make_unique<Derived_B>(ii) );
}

现在你没有delete任何东西,当vector超出范围时会调用析构函数(所以它的所有元素都是如此)

答案 3 :(得分:-1)

我建议使用{{1>} 智能指针(而不是原始拥有指针)。虽然原始观察指针很好,但拥有一个原始拥有指针的向量可能是潜在的泄漏源。

对于非共享所有权,请考虑使用 vector ,并使用vector<unique_ptr<Interface>>动态创建要添加到向量中的新项目。

使用 smart 指针的向量,可以编写更简单,更清晰的代码,因为C ++析构函数可以自动完成清理(换句话说,所有手动清理)使用原始拥有指针向量所需的代码就会消失。)