C ++ 11 метод std :: vector push_back так много раз вызывает copy / dest? - PullRequest
0 голосов
/ 26 декабря 2018

В настоящее время я оптимизирую свой код, и у меня есть вопрос относительно std :: vector

У меня есть класс MyClass, в который я переписал конструктор копирования / перемещения и соответствующие им операторы.

MyClass(const std::string& id, int x);
MyClass(const MyClass& other);
MyClass(MyClass&& other);
~MyClass();
MyClass& operator=(const MyClass& other);
MyClass& opratror*(MyClass&& other);

Я создал вектор и попробовал следующее

std::vector<MyClass> vec;
MyClass a("A", 1);
vec.push_back(a);    //#1
vec.emplace_back("B", 2);    //#2
vec.push_back(MyClass("C", 3));    //#3

в # 1 вызывается конструктор копирования (который, как я знаю, хранит вектор по значениям, поэтому он копирует a) в # 2он сохраняет вызов конструктора копирования, только вызывает конструктор в # 3, он вызывает конструктор и конструктор перемещения

Но я обнаружил, что в # 2, # 3, где вектор не пуст, каждый толчок назад /emplace / emplace_back запускает копирование / уничтожение существующих элементов.

в # 2, копирует «A» и уничтожает существующую «A» в # 3, делает то же самое с «A» и «B»

кажется, что вектор изменяет все элементы всякий раз, когда изменяется массив.Означает ли это, что использование вектора класса может сделать вещи неэффективными?Является ли это лучшим решением для использования вектора, хранящего указатели, чтобы при вызове не было вызовов копирования / деструкторов, а только копирование указателей?

Спасибо

Ответы [ 2 ]

0 голосов
/ 26 декабря 2018

Вам нужно сделать ход ctor noexcept(false);в противном случае во многих случаях его нельзя безопасно использовать.

Представьте себе, что в буфере помещается вектор из 10 элементов, который умещается в 10. Мы изменили его размер до 15 и переместили первые 3 из них.

Перемещение 4-х бросков.Как мы должны вернуть вектор в нормальное состояние?

Вместо этого стандарт C ++ требует, чтобы бросание не использовалось, и он копирует 10 элементов в новый буфер.Когда это удастся, он может затем уничтожить старый буфер.

Без перемещения, он может в обязательном порядке переместить 10 элементов в новый буфер.

0 голосов
/ 26 декабря 2018

Не курорты, но перераспределяет.По контракту вектор должен хранить свои значения непрерывно, как обычный массив.Единственный способ гарантировать непрерывное хранение - выделить один кусок памяти.Как только вы получили это, все готово.Вы не можете сделать это больше.Все, что вы можете сделать, это выделить больший кусок и скопировать все заново, а затем удалить старый меньший блок памяти.Это то, что вы видите.

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

Если вы заранее знаете, сколько значений вы собираетесь получить push_back (), вы можете использоватьreserve() заранее, чтобы заранее выделить дополнительное пространство и минимизировать перераспределение.

Если вы знаете, что вы собираетесь добавить еще десять значений к вектору:

vec.reserve(vec.size()+10);

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

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