C ++ vector push_back

时间:2011-09-11 23:46:31

标签: c++ vector

将新对象元素推送到std::vector的正确方法是什么?我希望数据在向量中分配。这会将对象newradio复制到向量中,然后在超出范围(例如,不在堆栈中)时删除newradio吗?

vector<Radio> m_radios;
Radio newradio(radioNum);
m_radios.push_back(newradio);

然后当我释放包含m_radios的对象时,它会释放向量分配的所有内存吗?

7 个答案:

答案 0 :(得分:34)

std::vector管理自己的记忆。这意味着,当调用向量的析构函数时,向量所占用的内存将被释放。 std::vector在删除对象时也会调用对象的析构函数(通过erasepop_backclear或向量的析构函数。)

执行此操作时:

Radio newradio(radioNum);
m_radios.push_back(newradio);

您将newradio(使用Radio的复制构造函数创建)的副本添加到向量中。当newradio超出范围时,它将被销毁,并且当从向量中移除副本时(例如任何对象),副本将被销毁。

这一点非常重要:std::vector只存储对象的副本,这意味着该对象必须具有有意义的复制构造函数(和赋值运算符,但这是另一个问题)。如果你有一个指针向量,那么指针本身将被复制,而不是指向它。请注意,此行为对于每个标准容器都是相同的(例如std::liststd::set)。

根据经验,如果你没有使用指针,那么你不必担心自己释放内存。

在C ++ 11中,大多数标准容器(包括vector)都有一个emplace_back方法,可以在容器的末尾构建一个到位对象。它需要一堆参数并调用最能匹配这些参数的构造函数(如果不存在这样的构造函数,则会失败),使用所述构造函数在容器的末尾创建没有任何副本的对象。因此,上面的代码可以改写为:

m_radios.emplace_back(radioNum); // construct a Radio in place, 
                                 // passing radioNum as the constructor argument

同样在C ++ 11中,容器通常是移动识别,因此它们不再需要对象可复制:如果它们可移动,则容器将移动其内容根据需要(例如在重新分配期间)。如果要复制矢量,仍然需要可复制类型。

答案 1 :(得分:4)

push_back()将在向量中存储其参数的副本。只要Radio实现了正确的值语义,就不会有问题。

答案 2 :(得分:1)

是的,推送newRadio会将Radio对象的副本推送到向量中。您也不需要释放向量,因为它只是本地的,因此一旦超出其范围就会被销毁。例如,如果你写了

vector<Radio> *m_radios = new vector<Radio>();

然后你必须通过手动调用vector析构函数来释放内存。

答案 3 :(得分:1)

试试这个:

#include<iostream.h>
#include<vector.h>

class base
{
int i;
public:

    base(int z=0){i=z;cout<<"okk constructor "<<i<<" called\n";}
    base(const base& b1){i=b1.i;cout<<"copy constructor "<<i<<" called\n";}
    void display(){cout<<" val is "<<i<<" \n";}
    ~base(){cout<<"destructor of "<<i<<" base called\n";}
};


    int main()
    {
        cout<<"before anything\n";
        vector<base> basev;
        base baseobj1(1);
        base baseobj2(2);
        base baseobj3(3);
        base baseobj4(4);
        base baseobj5(5);
        base baseobj6(6);
        base baseobj7(7);
        base baseobj8(8);
        base baseobj9(9);
        base baseobj10(10);


        basev.push_back(baseobj1);
        cout<<"second push back\n";
        basev.push_back(baseobj2);
        cout<<"third push back\n";
        basev.push_back(baseobj3);
        cout<<"fourth push back\n";
        basev.push_back(baseobj4);
        cout<<"fifth push back\n";
        basev.push_back(baseobj5);
        cout<<"sixth push back\n";
        basev.push_back(baseobj6);
        cout<<"seventh push back\n";
        basev.push_back(baseobj7);
        cout<<"eighth push back\n";
        basev.push_back(baseobj8);
        cout<<"ninth push back\n";
        basev.push_back(baseobj9);
        cout<<"10th push back\n";
        basev.push_back(baseobj10);
        cout<<"after all push back\n";


        cout<<"before clear\n";
        basev.clear();
        cout<<"after clear\n";


}

输出:

before anything
okk constructor 1 called
okk constructor 2 called
okk constructor 3 called
okk constructor 4 called
okk constructor 5 called
okk constructor 6 called
okk constructor 7 called
okk constructor 8 called
okk constructor 9 called
okk constructor 10 called
copy constructor 1 called
second push back
copy constructor 1 called
copy constructor 2 called
destructor of 1 base called
third push back
copy constructor 1 called
copy constructor 2 called
copy constructor 3 called
destructor of 1 base called
destructor of 2 base called
fourth push back
copy constructor 4 called
fifth push back
copy constructor 1 called
copy constructor 2 called
copy constructor 3 called
copy constructor 4 called
copy constructor 5 called
destructor of 1 base called
destructor of 2 base called
destructor of 3 base called
destructor of 4 base called
sixth push back
copy constructor 6 called
seventh push back
copy constructor 7 called
eighth push back
copy constructor 8 called
ninth push back
copy constructor 1 called
copy constructor 2 called
copy constructor 3 called
copy constructor 4 called
copy constructor 5 called
copy constructor 6 called
copy constructor 7 called
copy constructor 8 called
copy constructor 9 called
destructor of 1 base called
destructor of 2 base called
destructor of 3 base called
destructor of 4 base called
destructor of 5 base called
destructor of 6 base called
destructor of 7 base called
destructor of 8 base called
10th push back
copy constructor 10 called
after all push back
before clear
destructor of 1 base called
destructor of 2 base called
destructor of 3 base called
destructor of 4 base called
destructor of 5 base called
destructor of 6 base called
destructor of 7 base called
destructor of 8 base called
destructor of 9 base called
destructor of 10 base called
after clear
destructor of 10 base called
destructor of 9 base called
destructor of 8 base called
destructor of 7 base called
destructor of 6 base called
destructor of 5 base called
destructor of 4 base called
destructor of 3 base called
destructor of 2 base called
destructor of 1 base called

答案 4 :(得分:0)

是的,radioNum复制m_radios。只要你在newradio.~Radio();发生时(超出范围)你没有释放指针,那就没问题了。如果m_radios或子类使用指针,则需要切换到smart pointersshared_ptr)。

m_radios超出范围时,会自动调用析构函数,并释放所有std::vector所有的东西。

答案 5 :(得分:0)

除了通过调用复制构造函数使用push_back验证对象是否已复制到容器中的其他答案之外,您还可以记住添加了emplace_back的新功能。 {1}}。

调用c++0x允许您绕过任何临时对象的创建,并直接在容器内就地构建对象。 emplace_back是一个varardic模板函数,它接受你传递给对象构造函数的参数,所以在这种情况下:

emplace_back

不会创造任何中间临时工。如果您的对象复制成本很高,这可能会有所帮助。

希望这有帮助。

答案 6 :(得分:0)

默认情况下,std :: vector使用基础类的复制构造函数来管理内存本身。因此,它的作用有点像向量元素是一个局部变量(当向量超出范围时,元素被破坏)。

当你不想要这种行为时,你可以使用指针向量或者使用boost :: ptr_vector。