Подтвердить что ты не робот

С++ вектор push_back

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

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

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

Ответ 2

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

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

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

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

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

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

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

Ответ 6

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

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

Ответ 7

Попробуйте следующее:

#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