C ++ вектор push_back - PullRequest
       9

C ++ вектор push_back

18 голосов
/ 12 сентября 2011

Как правильно вставить новый элемент объекта в std::vector?Я хочу, чтобы данные были размещены в векторе.Будет ли это скопировать объект newradio в вектор, а затем избавиться от newradio, когда он выйдет из области видимости (например, из стека)?

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

И затем, когда я освобожу объект, содержащийm_radios, освободит ли это всю память, выделенную вектором?

Ответы [ 7 ]

36 голосов
/ 12 сентября 2011

std::vector управляет собственной памятью. Это означает, что когда вызывается деструктор вектора, память, содержащаяся в векторе, освобождается. std::vector также вызывает деструктор объекта при его удалении (через erase, pop_back, clear или деструктор вектора).

Когда вы делаете это:

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

Вы добавляете копию newradio (созданную с помощью конструктора копирования Radio) к вектору. newradio будет уничтожено, когда выйдет из области видимости, и копия будет уничтожена, когда будет удалена из вектора (как и для любого объекта).

Это важный момент: std::vector хранит только копий объекта, что означает, что у объекта должен быть значимый конструктор копирования (и оператор присваивания, но это другая проблема). Если у вас есть вектор указателей, то будет скопирован сам указатель, а не то, на что он указывает. Обратите внимание, что это поведение одинаково для каждого стандартного контейнера (например, std::list или std::set).

Как правило, если вы не используете указатели, вам не нужно беспокоиться об освобождении памяти самостоятельно.

В C ++ 11 большинство стандартных контейнеров (включая vector) имеют метод emplace_back, который создает объект вместо в конце контейнера. Он принимает набор параметров и вызывает конструктор, который лучше всего соответствует этим параметрам (или завершается неудачей, если такого конструктора не существует), используя указанный конструктор для создания объекта без какой-либо копии в конце контейнера. Таким образом, приведенный выше код можно переписать так:

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

Также в C ++ 11 контейнеры обычно знают о перемещении , поэтому им больше не требуется копирование объектов: если они подвижные , тогда контейнер будет перемещать свое содержимое по мере необходимости (например, во время перераспределения). Копируемые типы все еще требуются, если вы хотите скопировать вектор.

4 голосов
/ 12 сентября 2011

push_back() будет хранить копию своего аргумента в векторе.Пока Radio реализует правильную семантику значений, с этим не будет проблем.

1 голос
/ 17 января 2013

Попробуйте это:

#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
1 голос
/ 12 сентября 2011

Да, нажатие на newRadio подтолкнет копию объекта Radio в вектор. Вам также не нужно освобождать вектор, потому что он является локальным, поэтому он будет уничтожен, как только вы выйдете за его пределы. Если, например, вы написали

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

Тогда вам придется освободить эту память, вызвав деструктор вектора вручную.

0 голосов
/ 12 сентября 2011

По умолчанию std :: vector управляет самой памятью с помощью конструктора копирования базового класса. Таким образом, он действует немного, как если бы элемент вектора был локальной переменной (когда вектор выходит из области видимости, элемент разрушается).

Если вам не нужно это поведение, вы можете использовать вместо него вектор указателя или boost :: ptr_vector.

0 голосов
/ 12 сентября 2011

В дополнение к другим ответам, которые проверяют, что объект копируется в контейнер при использовании push_back через вызовы конструктора копирования, вы также можете иметь в виду новую функциональность emplace_back, добавленную с c++0x.

Вызов emplace_back позволяет вам обойти создание любых временных объектов и создать объект непосредственно внутри контейнера. emplace_back - это шаблонная функция varardic, которая принимает параметры, которые вы передадите конструктору вашего объекта, поэтому в этом случае:

std::vector<Radio> m_radios;
m_radios.emplace_back(radioNum);

не создаст промежуточных временных. Это может быть полезно, если ваши объекты копируются дорого.

Надеюсь, это поможет.

0 голосов
/ 12 сентября 2011

Да, radioNum будет скопировано в m_radios.Пока вы не освобождаете указатели, когда появляется newradio.~Radio(); (вне области видимости), все в порядке.Если m_radios или в подклассе используются указатели, вам необходимо переключиться на интеллектуальные указатели (shared_ptr).

Когда m_radios выходит за пределы области действия,автоматически вызывается деструктор, и все, что хранит std::vector, освобождается.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...