Most of it depends on which container you are talking about, and how you are using it.
vector usually has the smallest footprint, except at the moment you add an element that is beyond the current vector capacity. At that moment it it will allocate something like 1.5 x the current vectors capacity, move the elements (or in the worst case make a new copy which also allocates memory) and when that is done, delete the old vectors internals, If you know how many elements it is going to hold up front, vector with a use of reserve is your best bet.
The second smallest is list. It has the advantage that its not going to make a temporary copy of itself. After that set is your best bet is probably set. Some implementation have slist now, which is smaller. In these cases tt is pretty easy to make an allocator that packs the memory in pages.
Stay away from memory hogs like unordered_*
On MSVC be sure to #define _SECURE_SCL=0 This takes out a lot of overhead used for secure programming checks (like buffer overruns, etc)
By far the most memory efficient containers are boost/intrusive These have extremely small footprints since they use the memory of the thing being contained. So instread of going to the heap for a small chunk of memory for a linked list or rb tree node, the node pointers are part of the object itself. Then the "container" is just one raw set of a few pointer to make a root node. I've used it quite a few times to get rid of footprint and allocation overhead.