Reputation: 2321
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.
std::map
(also uses Red-Black trees) has an extra key, but still 24 bytes? Why?
Why std::queue
and std::stack
take 40 bytes while std::vector
takes only 12 bytes?
Why char
and double
does not affect the size of the class? Is it because of the templates?
Upvotes: 3
Views: 5132
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
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
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
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
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