2016-11-01 5 views
5

я немного запутался в последнее время о распределении памяти (де) из std::vectorsВопросы по memorybehavior векторов

Давайте предположим, что я нормальный вектор целого числа: std::vector<int> intv; Когда я push_back некоторые int «S Произрастает по времени. И когда я покидаю область действия (т. Е.) Функции, она освобождается без необходимости дополнительных вызовов.

Отлично. Еще один пример:

struct foo_t{ 
    std::string bar: 
    unsigned int derp; 
} 
void hurr(){ 
    std::vector<foo_t> foov; 
    foo_t foo; 
    foo.bar = "Sup?"; 
    foo.derp = 1337; 
    foov.push_back(foo); 
} 

Хорошо. Когда я вызываю hurr(), вектор создается, создается экземпляр foo_t, экземпляр заполняется и переносится на вектор. Поэтому, когда я покидаю функцию, вектор становится освобожденным, и содержимое (здесь одно foo_t) также освобождается?

Следующий пример:

struct foo_t{ 
    std::string bar: 
    unsigned int derp; 
} 
std::vector<foo_t> hurr(){ 
    std::vector<foo_t> foov; 
    foo_t foo; 
    foo.bar = "Sup?"; 
    foo.derp = 1337; 
    foov.push_back(foo); 
    return foov; 
} 

В моем понимании, вектор и его содержимое живут в стеке, который получает (в конечном счете) переписывается времени и вектор я вернулся, и его содержание будет бесполезно. Или он действительно возвращает копию вектора с копией его содержимого (для этого требуется экземпляр Copy-Constructor, если он не POD)?

И что-то очевидное:

struct foo_t{ 
    std::string bar: 
    unsigned int derp; 
} 
std::vector<foo_t*> hurr(){ 
    std::vector<foo_t*> foov; 
    foo_t foo = new foo_t; 
    foo->bar = "Sup?"; 
    foo->derp = 1337; 
    foov.push_back(foo); 
    return foov; 
} 

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

+0

_ «Теперь мне нужно вручную перебирать вектор, удалять его содержимое, а затем я могу смело разрешить вектор выпадать из сферы действия, правильно?» _ Да. –

+1

«Теперь мне нужно вручную перебирать вектор, удалять его содержимое, а затем я могу смело позволить вектору выпасть из области действия, верно?» Это приведет к недействительности указателей в возвращаемом векторе. Если это не то, что вы хотите, и это, вероятно, нет, вы не должны. – molbdnilo

+0

@molbdnilo Зависит от того, когда предполагается _Now_. –

ответ

3

В этом примере:

struct foo_t{ 
    std::string bar; 
    unsigned int derp; 
}; 
void hurr(){ 
    std::vector<foo_t> foov; 
    foo_t foo; 
    foo.bar = "Sup?"; 
    foo.derp = 1337; 
    foov.push_back(foo); 
} 

После того, как закончено hurv(), foov и foo оба освобождены.

std::vector<foo_t> hurr(){ 
    std::vector<foo_t> foov; 
    foo_t foo; 
    foo.bar = "Sup?"; 
    foo.derp = 1337; 
    foov.push_back(foo); 
    return foov; 
} 

std::vector<foo_t> результат из hurr() действителен с 1 foo_t в нем, и она действует. return foov;может назвать копию застройщик из std::vector<foo_t>, и есть его бесплатно, чтобы не сделать эту копию, см copy elision

Во всяком случае, от C++ 11, вы можете написать следующее:

struct foo_t{ 
    std::string bar; 
    unsigned int derp; 
    // we will copy the string anyway, pass-by-value 
    foo_t(std::string bar_, unsigned int d_) 
     : bar(std::move(bar_)), derp(d_) {} 
}; 
std::vector<foo_t> hurr(){ 
    std::vector<foo_t> foov; 
    // This is better, in place construction, no temporary 
    foov.emplace_back("Sup?", 1337); 
    // This require a temporary 
    foov.push_back(foo_t{"Sup?", 1337}); 
    return foov; 
} 

И, для последнего примера, да, вы, , должны вручную перебирать вектор, удалять его содержимое, а затем я могу смело разрешить вектор выпадать из области, когда вы больше не хотите использовать результат hurr(), (не в hurr())

+0

вы пропустили точку 'emplace_back'. Все дело в том, чтобы построить на месте, избегая необходимости в временном. Вы должны сделать 'emplace_back (« sup », 1337)' – bolov

+0

@bolov на самом деле, он не может быть скомпилирован с помощью 'emplace_back (« sup », 1337)', 'emplace_back' нужен конструктор, правильно? – Danh

+0

да, но 'emplace_back' будет делать то же самое, что и' push_back' в этом случае, т. Е. Переместить временное в вектор. – Asu

2

Так что, когда я покидаю функцию, вектор освобождается и содержимое (здесь один foo_t) также освобождается?

Да. И если бы foo_t имел нетривиальный деструктор, он был бы назван.

Или это на самом деле возвращает копию вектора с копией его содержимого (требуется Copy-конструктор для типа данных контента, если его не стручок)?

Да, в этом случае он возвращает копию. Современные компиляторы, вероятно, вызовут конструктор копирования для std::vector, который, в свою очередь, вызовет конструктор копирования содержащегося типа для каждого элемента. C++ 17 представляет гарантированную оптимизацию возвращаемого значения (RVO), поэтому конструктор копирования вашего вектора не будет вызываться. Тем не менее, если вы установите высокий уровень оптимизации, современный компилятор может также использовать RVO.

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

Да, вы правы. Рассмотрите возможность использования интеллектуальных указателей, если вы не хотите, чтобы итерация выполнялась вручную.

+0

В моей [тестовой программе] (http://coliru.stacked-crooked.com/a/3442c38380fbe573), g ++ в '-O0' * на самом деле *, похоже, использует RVO. * edit: * Я фактически не компилировал в '-O0' в этой программе, но если вы укажете его, вы получите те же результаты. – Asu

+0

Использование smartpointers было другим примером для моего вопроса, который я забыл. –

+0

Даже если нет никакого разрешения на копирование, будет использован конструктор move (если содержащийся тип невозможен) –

3
foov.push_back(foo); 

На самом деле, вы построили foo_v и вы толкнул его обратно, который фактически создал новый foo_v и называется конструктор копирования с foov как paremeter. Используйте emplace_back, если вы хотите этого избежать.

return foov; 

Компилятор может оптимизировать это с использованием оптимизации возвращаемого значения. См. this short program В качестве примера я сделал запуск на coliru. Обратитесь к другим отличным ответам в this question.

std::vector<foo_t*> foov; 
/* add elements to foov with new */ 

Теперь я должен вручную itterate над вектором, удалите его содержимое, а затем я могу смело пусть вектор выпадают из сферы, не так ли?

Да, это так. По тем же причинам

int* a = new int(); 

не delete a; Смогут когда a плашек.