banarun
banarun

Reputation: 2321

sizeof() on C++ Standard Library

I got curious and applied sizeof() operator on some C++ standard Library Classes. Here is what I have observed:

int main() 
{
    vector<double> v1;
    set<double> s1;
    map<double,double> m1;

    stack<char> st;
    queue<char> q;

    vector<char>  v2;
    set<char> s2;
    map<char,char> m2;

    cout<<sizeof(v1)<<" "<<sizeof(s1)<<" "<<sizeof(m1)<<endl;
    cout<<sizeof(v2)<<" "<<sizeof(s2)<<" "<<sizeof(m2)<<endl;
    cout<<sizeof(q)<<" "<<sizeof(st)<<endl;
    return 0;
}

The output on my system (64-bit) is:

12 24 24
12 24 24
40 40

I know that std::set uses Red-Black tree for implementation. So a each node of a binary tree has two pointers(8 bytes each) and the value(8 bytes, total 24) seems alright.

  1. std::map(also uses Red-Black trees) has an extra key, but still 24 bytes? Why?

  2. Why std::queue and std::stack take 40 bytes while std::vector takes only 12 bytes?

  3. Why char and double does not affect the size of the class? Is it because of the templates?

Upvotes: 3

Views: 5132

Answers (5)

Mats Petersson
Mats Petersson

Reputation: 129524

The sizeof operator will give you the size of a type.

Now, if I were to make an very simplified version of the std::vector<T> here (note this doesn't do ANYTHING as much as a REAL implementation does, and it's far too simplified to really work - and I'm skipping over lots of bits that you really need in a real one):

template<typename T>
class vector<T>
{
   public:
      typedef size_t size_type;
   private:
     T* mdata;
     size_type msize;
     size_type mreserved;
   public:
     vector() { mreserved = msize = 0; mdata = 0; }
     vector(size_type sz) { msize = 0; mreserved = sz; mdata = new T[sz](); }
     void push_back(const T& v) 
     { 
        if (msize + 1 > mreserved) grow(mreserved * 2);
        mdata[msize+1] = v;
        msize++;
     }
     size_type size() const { return msize; }
     // bunch of other public functions go here. 
   private:
     void grow(size_type newsize)
     {
        if (newsize < 8) newsize = 8;
        T* newdata = new T[newsize]; 
        for(size_type i = 0; i < msize; i++) newdata[i] = mdata[i];
        swap(mdata, newdata);
        delete [] mdata;
        mreserved = newsize;
     }
  };

As you can see, the size of the actual class is identical (it contains the same size and number of elements) no matter how large the set of data stored is. In other words, the sizeof(vector<int>) is constant. The size of the data stored behind mdata is of course changing, but sizeof doesn't know (can't know) that.

Upvotes: 5

Armen Tsirunyan
Armen Tsirunyan

Reputation: 133112

This sample source code will give you the idea:

struct A
{
    int* p; //4 bytes
    A(int n)
    {
        p = new int[n];
    }  
};

int main()
{
    A x1(10);   
    A x2(100);  
    cout << boolalpha << (sizeof(x1) == sizeof(x2)); //prints true
}

The reason is that A only contains a pointer. The size of the pointer is always the same (usually 4). It doesn't matter what the pointer points to - a dynamic array of 1000 or 1000000. It's still 4.

Char or double does not affect the size because a pointer to char has the same size as the pointer to double.

For an std::array, which actually holds an array, not a pointer, these would matter (both the array type and size):

cout << boolalpha << ((sizeof(std::array<int, 10>) == sizeof(std::array<int, 11>)); //false!
cout << boolalpha << ((sizeof(std::array<int, 10>) == sizeof(std::array<long double, 10>)); //false!

Upvotes: 4

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385395

You seem to be assuming that the size of a container class can increase with the number of elements consumed, but this is physically impossible as all types have a fixed size.

Instead, elements are stored indirectly using dynamic allocation;
sizeof will not reveal this information to you.

The only information that sizeof gives you is how many pointers, counters, flags and other metadata are used in the construction and management of the container; this sort of detail is abstracted away from you and you should never attempt to rationalise about it.

Upvotes: 2

Some programmer dude
Some programmer dude

Reputation: 409442

The implementation of these classes is a black box, there is no way of telling what data or private members they contain. It's totally up to the implementation.

The only way to know what all the bytes in the object instance are, is to read the source code.

Upvotes: 6

Bathsheba
Bathsheba

Reputation: 234865

It's important to remember that sizeof is evaluated at compile time: so it is not, in any sense, dynamic.

Its job is to return the size of the class / structure / plain old data; nothing else.

That is why it always gives the same results for your vectors, sets and maps.

Upvotes: 2

Related Questions