Внутренняя работа вектора в C ++? - PullRequest
3 голосов
/ 23 сентября 2011

Я работаю над упражнением на C ++, но получаю неожиданный вывод. Я надеюсь, что кто-то может объяснить.В упражнении было предложено создать класс с именем rock, который имеет конструктор по умолчанию, конструктор копирования и деструктор, которые объявляют себя cout.

В основном методе я пытаюсь добавить членов этого класса в вектор по значению:

vector<Rock> byValue;
Rock r1, r2, r3;
byValue.push_back(r1);
byValue.push_back(r2);
byValue.push_back(r3);
cout << "byValue populated\n\n";

Результат, который я ожидал (и показан в решениях для упражнений):

Rock()
Rock()
Rock()
Rock(const Rock&)
Rock(const Rock&)
Rock(const Rock&)
byValue populated

~Rock()
~Rock()
~Rock()
~Rock()
~Rock()
~Rock()

Однако вывод, который я получаю:

Rock()
Rock()
Rock()
Rock(const Rock&)
Rock(const Rock&)
Rock(const Rock&)
~Rock()
Rock(const Rock&)
Rock(const Rock&)
Rock(const Rock&)
~Rock()
~Rock()
byValue populated

~Rock()
~Rock()
~Rock()
~Rock()
~Rock()
~Rock()

Может кто-нибудь объяснить, почему, похоже, существуют дополнительные вызовы конструктора и деструктора копирования?

Ответы [ 3 ]

8 голосов
/ 23 сентября 2011

При изменении размера вектора элементы должны быть перемещены на новое место.

Это нормально.

Если вы звоните

byValue.reserve(10);

дозвонки на push_back, лишние копии должны исчезнуть.

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

Вектор хранит свои элементы непрерывно. Чтобы избежать всегда перераспределения памяти каждый раз, когда вставляется элемент, он выделяет кучу памяти. Вот почему у вектора есть два метода относительно его размера: size(), который сообщает количество хранимых элементов, и capacity(), который указывает объем выделенной памяти.

Обычно (но это зависит от реализации STL), он увеличивается за счет удвоения своей предыдущей емкости. Когда он выделяет больше памяти и поскольку данные должны храниться непрерывно (по сравнению с list), он должен перемещать свои внутренние данные; и STL копирует данные, поэтому у вас так много обращений к конструктору / деструктору.

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

1 голос
/ 23 сентября 2011

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

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

Глядя на ваш вывод, кажется, что вектор должен был вырасти вдвое.Если вы изменили код на функцию резервного вызова, прежде чем нажимать что-либо, вектор никогда не будет нуждаться в увеличении и дополнительных копий не будет.

Вот подробный фрагмент кода, который показывает, как все это объединяется:ideone.com

...