Мой вопрос об оптимизации функции vector::erase
.
Поскольку мы знаем, что вектор является непрерывным блоком памяти, а также знает каждый размер элемента в контейнере, почему метод vector<myclass> v
erase(v.begin())
все еще вызывает все деструкторы элементов в v
? Может ли это сделать пошаговую смену?
Пример: скажите, что у вас есть
//compiled with g++ 4.7
#include<iostream>
using namespace std;
class barebone{
public:
~barebone(){
cout << "1" << endl;
}
};
int main(){
vector<barebone> x(5);
x.erase(x.begin());
cout << "done" << endl;
}
Это вызовет деструктор для каждого элемента в контейнере (5 раз). Это покажет 5. чересстрочный сдвиг будет быстрее и вызовет деструктор только один раз
EDIT: из деструктора вызова ответа delete() один раз с выходом
1 сделано 1 1 1 1
Деструктор должен быть вызван только для стирания элемента (ов); если вы видите, что это вызвано для других, то ваша реализация vector
не соответствует. С++ 11 23.3.6.5 указывает
Сложность: деструктор T называется числом раз, равным числу стираемых элементов, но оператор назначения перемещения для T называется числом раз, равным числу элементов в векторе после стираемых элементов.
Старые стандарты указывали аналогичное поведение, но с копией, а не с перемещением.
Ваш пример показывает 1
пять раз, потому что остальные деструкторы вызываются, когда вектор уничтожается в конце main
. Вы можете увидеть это более четко, если вы выведете что-то сразу после вызова для erase
.
operator = (Foo other)
вместо const Foo &other
, временное значение будет уничтожаться каждый раз. Использование Foo other
вместо const Foo &other
было предложено в теме под названием What is the copy and swap idiom
для некоторой оптимизации или w / e. В любом случае, +1 от меня. Я думал, что придется уничтожить все элементы, несмотря ни на что ..
Я не покупаю его. Я написал тестовую программу, и после удаления деструктор вызывается только один раз. Я предлагаю вам сделать то же самое и убедиться в этом сами.
#include <iostream>
#include <vector>
using namespace std;
class TestObject
{
public:
static int counter;
TestObject() { std::cout << "constructed!" << std::endl; }
~TestObject() { std::cout << "destructed!" << std::endl; counter++;}
};
int TestObject::counter = 0;
int main()
{
std::vector<TestObject> to(5);
to.erase(to.begin());
std::cout << "destructed " << TestObject::counter << " times" << std::endl;
to.push_back(TestObject());
return 0;
}
Вот результат.
Компиляция исходного кода.... $g++ -std = С++ 11 main.cpp -o demo -lm -pthread -lgmpxx -lgmp -lreadline 2> & 1
Выполнение программы.... $ demo построено! построен! построен! построен! построен! подорванный! разрушено 1 раз построено! подорванный! подорванный! подорванный! подорванный! подорванный! подорванный!
Ясно, что деструктор выполняется один раз после удаления. Теперь, если у вас было стирание, как последнее, за которым следует cout в вашем собственном примере, возможно, что вы подумали, что он был уничтожен 5 раз стиранием.