2017-01-26 2 views
7

У меня есть возраст, пытаясь понять, почему это происходит.Почему этот объект не уничтожается?

struct Element 
    { 
     Element(int number) : number_ID(number) 
     { std::cout << "Element number " << number_ID << " is being constructed\n"; } 
     ~Element() 
     { std::cout << "Element number " << number_ID << " is being destroyed\n"; } 
     int number_ID; 
    }; 

    void createVector() 
    { 
     std::vector<Element> objArr; 
     objArr.reserve(10);  // So it doesn't have to reallocate 

     objArr.emplace_back(1); 
     objArr.emplace_back(2); 
     objArr.emplace_back(3); 
     objArr.emplace_back(4); 

     objArr.erase(objArr.begin());  // When I erase the first element only element 4 has destructor called 
    } 

    int main() 
    { 
     createVector(); 


     system("pause"); 
    } 

я получаю: не

Element number 1 is being constructed 
Element number 2 is being constructed 
Element number 3 is being constructed 
Element number 4 is being constructed 
//The following called when doing objArr.erase(objArr.begin()); 
Element number 4 is being destroyed 
//The following called after createVector() function exits 
Element number 2 is being destroyed 
Element number 3 is being destroyed 
Element number 4 is being destroyed 

Деструктор для элемента 1 не вызывается? Сначала я не знал, почему деструктор элемента номер 4 будет вызван при стирании первого элемента, а затем я подумал, что когда он меняет своих членов, возможно, деструктор должен быть вызван. Но в документации говорится, что все члены после удаленной передачи смещаются, а деструкторы 2 и 3 не вызываются. Я действительно смущен.

EDIT: Ну, если это шаг оптимизации, то документация неправильно, потому что:

Удаляет из вектора либо один элемент (положение) или диапазон элементов ([первый, последний)).

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

Это не разрушает тогда.

+0

Вы удаляете первый элемент. Все последующие элементы скопированы/перемещены (по назначению) влево, чтобы заполнить пустое пространство. После этого элемент хвоста разрушается. Это то, что вы видите. – AnT

+0

@AnT Я не понимаю, я думал, что вектор всегда осторожен, чтобы называть любые деструкторы, например, при перераспределении он должен вызывать все деструкторы. Так что, если мне нужен деструктор, я должен сам это назвать? – Zebrafish

+1

Но в этом случае не нужно вызывать несколько деструкторов. Перераспределения нет. И перемещение элементов естественно достигается цепочкой заданий. Итак, все, что вам нужно, это уничтожить хвостовой элемент после этих переназначений. Вы также можете думать о назначении как о разрушении, а затем о немедленном создании его LHS: вам нужно уничтожить старое значение LHS и построить в нем новое значение. В этом смысле все остальные элементы «разрушаются» и «реконструируются». – AnT

ответ

14

vector пытается сэкономить производительность.

Что делает erase, он копирует элементы 2, 3 и 4 вниз по одному элементу, перезаписывая элемент, содержащий 1. Таким образом, первый элемент теперь содержит 2 и т. Д. Затем он уничтожает последний элемент, который является копией 4.

Это приводит к стиранию первого элемента, но не совсем так, как вы думали. Он стирает содержимое первого элемента, но не сам объект.

В зависимости от типа, который вы храните в своем vector, это будет менее дорогостоящим, чем уничтожение первого элемента, только для восстановления копии второго элемента в хранилище первого.

Ну, если это шаг оптимизации, то документация неправильно, потому что:

...

Это не разрушая то.

Документация правильная, и она уничтожает их.

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

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

+0

Первый элемент содержит OpenGL VBO ID, который я должен удалить, о человеке. – Zebrafish

+9

@TitoneMaurice: тогда ваш класс *** не должен копироваться! *** Класс, который является скопированным, представляет собой класс, в котором два экземпляра могут иметь одно и то же значение, и вы можете передавать значения от одного к другому. Это не то, что вы хотите. [Так вы инкапсулируете объекты OpenGL] (http://stackoverflow.com/documentation/opengl/7556/encapsulating-opengl-objects-with-c-raii#t=201701260337507343073) –

+0

Человек, мне следовало бы написать доказательство займет слишком много времени. Ну хорошо: http://ideone.com/vlxlae – user4581301

Смежные вопросы