3

The sizeof() operator in C gives the size of its operand at compile time. It does not evaluate its operand. For example,

int ar1[10];
sizeof(ar1) // output 40=10*4
sizeof(ar1[-1]) // output 4
int ar2[ sizeof(ar1) ]; // generate an array of 40 ints.

When it came to C++ template class, I find some strange result.

template<typename T>
struct S{
    T a;
};

sizeof( S<int> )       // output 4
sizeof( S<bool> )      // output 1
sizeof( vector<int> )  // output 24
sizeof( vector<char> ) // output 24
sizeof( vector<bool> ) // output 40

I guess the sizeof on vector or other STL container depends on specific environment.

Question 1. How is sizeof implemented in C/C++? It cannot be a run-time function. Is it a macro? (what I learned in a online tutorial vedio). If it is a Macro, what the #define of it looks like? When the sizeof() is executed?

Question 2. If I add a member method void f(){} to the definition of struct S. The sizeof(S<int>) is still 4. Shouldn't the size of the struct increase?

Question 3. STL containers are template classes. Take vector for example, it has 12 member attributes/types and many member methods? It is easy to explain the output of sizeof( S<int> ). But I find it hard to explain the output of sizeof( vector<int> ). Template class should be instantiated at compile-time and the compiler should have total knowledge of the size of the class, i.e. vector<int>. So should sizeof() operator know.

Andrey Chernukha
  • 21,488
  • 17
  • 97
  • 161
Peng Zhang
  • 3,475
  • 4
  • 33
  • 41
  • 2
    You asked too many questions at once. Question 2 is answered here: http://stackoverflow.com/questions/8058213/do-class-methods-increase-the-size-of-the-class-instances – Slava Jul 24 '14 at 19:14
  • sizeof is a keyword in C/C++. I haven't see a name of Macro become a keyword. Maybe sizeof is not a macro. – Peng Zhang Jul 24 '14 at 19:15
  • @Slava Thanks. Honestly, I will not use sizeof in those strange way in my code. Just feel too ignorant about the behavior of sizeof. – Peng Zhang Jul 24 '14 at 19:16
  • Which video said `sizeof` was a macro? – chris Jul 24 '14 at 19:33
  • @chris It is explained in a chinese vedio at http://edu.51cto.com/lesson/id-30061.html – Peng Zhang Jul 24 '14 at 19:38
  • sizeof(int) or sizeof(char) as the name suggest, means allocate a memory of the given type whose byte size is int or bol or string. An int size is 4 byte, bol size is 1 byte. so if you create an int array of 10 elements. The total byte allocated will be 10 * 4 = 40 bytes long. – Juniar Jul 25 '14 at 01:49

2 Answers2

6

As per Question 1: sizeof is implemented and evaluated by the compiler. It is not a macro, and it always provides a compile-time result. Conceptually, you can imagine that the compiler replaces every sizeof with a number.

As per Question 2: sizeof counts the amount of storage that one instance of S occupies. A method does not take per-instance storage, only fields do (since they exist once per instance). A method does, however, occupy static storage somewhere to hold the machine code for the function.

As per Question 3: For sizeof(vector<int>) the compiler computes the size of the vector<int>, which it instantiates in order to do so. If you are confused because a vector can be of variable size: that is true, but the extra storage is allocate from the heap and thus not reflected in the result of sizeof applied to a vector.

Alexander Gessler
  • 45,603
  • 7
  • 82
  • 122
  • Q2 unless it is a first virtual function which will add some storage, this q already answered here http://stackoverflow.com/questions/8058213/do-class-methods-increase-the-size-of-the-class-instances – Slava Jul 24 '14 at 19:18
  • @Slava that should be considered as "implementation dependant" or "de facto standard", the point is that that kind of requirement is imposed by the implementation details about virtual functions, not by virtual functions themselves as dictated by the standard. – user2485710 Jul 24 '14 at 19:23
  • The elements of vector is only known at run-time. So the sizeof(vector<>) doesn't know it at all. But vector<> is a class. It only takes up 24 bytes? Also, why vector takes up 40 bytes? 24 and 40 may not be that important. Strange thing is that 40>24. – Peng Zhang Jul 24 '14 at 19:25
  • 3
    `std::vector` is an explicitly called out specialization which may use more space than a normal vector. – Mark B Jul 24 '14 at 19:26
  • 1
    @PengZhang `vector` it's a really weird data structure, it's basically one of the few exceptions to the rules inside the standard C++ library; just skip it. – user2485710 Jul 24 '14 at 19:28
  • @PengZhang A `std::vector` is, simplified, a class that holds an integer for the size of the vector and a pointer to the actual element storage on the heap. `sizeof` only computes the compile-time size of these, _direct_ fields of `std::vector` - it cannot and would not take the storage taken on the heap into account. – Alexander Gessler Jul 24 '14 at 19:36
  • @AlexanderGessler Thank. I am sure the elements of vector does not count for sizeof. But the vector template has 12 members. So should the vector. I just think 24 bytes cannot hold those 12 members as I see here http://www.cplusplus.com/reference/vector/vector/?kw=vector – Peng Zhang Jul 24 '14 at 19:42
  • 1
    @PengZhang, Those are type aliases. They don't take up per-instance space. – chris Jul 24 '14 at 19:46
  • @chris type alias? you mean like `typedef` or `#define`. I have little (or no) knowledge of implementation of STL. So there are not 12 member attributes of vector ? Thanks a lot! – Peng Zhang Jul 24 '14 at 19:49
  • @user2485710 Thanks. I see. `vector` is a template specialization. – Peng Zhang Jul 24 '14 at 19:50
  • 1
    @PengZhang, `typedef`. `#define` can't do that (reliably). This extends far beyond the C++ STL. The point is so you can say `vector::size_type` to get the type that, e.g., `size()` returns. The actual number of data members is up to the implementation. – chris Jul 24 '14 at 19:55
5
  1. sizeof is not a macro. It is a built-in operator and yields a constant expression, so you can imagine that the compiler just replaces it at compile-time with a literal whose value is the size of the object or class operand.

  2. Functions don't take up space inside objects. The code for the function is not stored inside the object.

  3. The size of a container such as std::vector<int> is the amount of memory taken up by the vector's members, plus some implementation-defined padding. It does not include any memory that the vector "owns" by holding pointers. (Note that elements of the vector are not members---when I say members I mean the members declared in the definition of the std::vector class.) So it's independent of how many elements are inside the vector.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • Functions don't take up space inside objects. The code for the function is not stored inside the object - Well, i'm just curious. An object must still hold a pointer to its function, i believe, and if it's true then this pointer takes few bytes of memory, doesn't it? – Andrey Chernukha Jul 24 '14 at 19:24
  • 2
    @AndreyChernukha No. If the function is not virtual, then the compiler can determine its address at compile time; calling the member function doesn't require examining the object. If the function is virtual, there's generally only a *single* pointer added to the object, which points to a table stored somewhere else that gives the addresses of *all* virtual functions for the object's class. – Brian Bi Jul 24 '14 at 19:26
  • Thanks a lot for a good answer. It is hard to choose the other one. – Peng Zhang Jul 24 '14 at 19:54