new and delete for very small objects is typically inefficient, vector
or not. Assuming that your new/delete is pointing to a general purpose
heap allocator underneath the hood (typically malloc ) why is this?
1. each call to new requires scanning free blocks looking for enough
space. This is typically and O(log n) search (where 'n' is the number
of free blocks)
2. In addition to the sizeof(int) memory required, you allocator is
going to add its own bookkeeping, usually sizeof(a few pointers). Plus
the minimum size chunk it is going to make is typically 16 bytes.
Since int only needs four, you've just claimed about 20 bytes extra
3. On an MT system, new/delete is going to cost you a mutex lock
4. delete is typically an O(n) operation (n being the number of times
you called new). If you ran your program through a very good profiler,
you would consistently find that "delete" operation take up way more
time than "new" (This is one reason that people find throwing an
exception very costly - as it is unwinding the stack, it is calling a
bunch of destructors, and dtor is where you find a lot of "deletes" )
5. There is no guarantee that the memory returned by successive calls
to "new" is placed anywhere near each other in memory. So your
processors cache keeps getting flushed and reloaded. Also, recall
that a typical L1 cache line is 16 bytes. Well, we just observed that
memory returned by new is going to take up about 20 odd bytes minimum.
So each 4 byte int needs an entire cache line. Ouch
6. the memory returned by new has maximum alignment, no matter what
type you are actually newing. No optimization can be performed based
on the fact that int does not always need maximum alignment.
OK so what does vector do? It just keeps one big contiguous chunk of
ints. So all of the observations above are amortized over many many
ints (in your example everything is done in reserve() and dtor), and
your cache likes it because all these ints are perfectly aligned and
jammed right next to each other.
You may also want to consider using deque if you are doing a lot of
insertions like your example. Seehttp://
www.codeproject.com/vcpp/stl/vector_vs_deque.asp
The moral of the story: only use container of pointers when
a) you need the object shared by other containers or some other object
b) the object is expensive to copy (large or complicated objects), or
is not copyable at all
c) you are making a container of abstract classes (you have no other
choice but use a pointer
Excessive calls to new is often a problem seen in C++ programs written
by Java developers. The Java allocator is completely different, and
the language itself accounts for this difference (one reason there are
no dtors in Java). Typically in Java, calls to new are constant time
(not including time to call objects ctor) and deallocation is behind
the scenes, outside of normal program flow. Of course, Java systems
developers are always struggling with Java's deallocation problems,
but that is a different story.
For delete, the easiest way is to use a shared_ptr . But if you have
performance worries now, using shared_ptr for a vector of int* is even
worse. This is how I do it
template<class T>struct deleteme{
void operator()(T t){delete t;}};
std::for_each(mycontainer.begin(),mycontainer.end(),deleteme<int*>());
Lance