Быстрая проверка утверждения Мартина Йорка о том, что это преждевременная оптимизация, и что новые / удаляются оптимизируются гораздо дальше, чем просто программисты могут улучшить. Очевидно, что спрашивающий должен будет приурочить свой собственный код, чтобы увидеть, помогает ли ему избегать нового / удаления, но мне кажется, что для определенных классов и применений это будет иметь большое значение:
#include <iostream>
#include <vector>
int g_construct = 0;
int g_destruct = 0;
struct A {
std::vector<int> vec;
A (int a, int b) : vec((a*b) % 2) { ++g_construct; }
~A() {
++g_destruct;
}
};
int main() {
const int times = 10*1000*1000;
#if DYNAMIC
std::cout << "dynamic\n";
A *x = new A(1,3);
for (int i = 0; i < times; ++i) {
delete x;
x = new A(i,3);
}
#else
std::cout << "automatic\n";
char x[sizeof(A)];
A* yzz = new (x) A(1,3);
for (int i = 0; i < times; ++i) {
yzz->~A();
new (x) A(i,3);
}
#endif
std::cout << g_construct << " constructors and " << g_destruct << " destructors\n";
}
$ g++ allocperf.cpp -oallocperf -O3 -DDYNAMIC=0 -g && time ./allocperf
automatic
10000001 constructors and 10000000 destructors
real 0m7.718s
user 0m7.671s
sys 0m0.030s
$ g++ allocperf.cpp -oallocperf -O3 -DDYNAMIC=1 -g && time ./allocperf
dynamic
10000001 constructors and 10000000 destructors
real 0m15.188s
user 0m15.077s
sys 0m0.047s
Это примерно то, что я ожидал: код в стиле GMan (уничтожить / разместить новое) занимает в два раза больше времени и, вероятно, занимает в два раза больше ресурсов. Если член вектора A заменяется на int, то код в стиле GMan занимает доли секунды. Это GCC 3.
$ g++-4 allocperf.cpp -oallocperf -O3 -DDYNAMIC=1 -g && time ./allocperf
dynamic
10000001 constructors and 10000000 destructors
real 0m5.969s
user 0m5.905s
sys 0m0.030s
$ g++-4 allocperf.cpp -oallocperf -O3 -DDYNAMIC=0 -g && time ./allocperf
automatic
10000001 constructors and 10000000 destructors
real 0m2.047s
user 0m1.983s
sys 0m0.000s
В этом я не так уверен: теперь удаление / новый занимает в три раза больше времени, чем деструктор / размещение новой версии.
[Edit: я думаю, что я понял это - GCC 4 быстрее на 0-размерных векторах, фактически вычитая постоянное время из обеих версий кода. Изменение (a*b)%2
на (a*b)%2+1
восстанавливает соотношение времени 2: 1 с 3,7 с против 7,5]
Обратите внимание, что я не предпринял никаких специальных шагов для правильного выравнивания массива стека, но печать адреса показывает, что он выровнен по 16.
Кроме того, -g не влияет на время. Я оставил его случайно после того, как посмотрел на objdump, чтобы проверить, что -O3 не полностью удалил цикл. Эти указатели назывались yzz, потому что поиск «y» прошел не так хорошо, как я надеялся. Но я просто перезапущен без него.