Identifying exact heap and stack memory in program?

Hi I got some help earlier on a problem similar to this which helped me find stack values for
"List myList;": stack 8,
"List *special = new List(10);": stack 4,
unknown about "List lists[5];"
all within int main

Not sure what the heap is for any of the individual calls when ran, don't know stack for last one, here is code:

https://pastebin.com/kH4Qgq2h
Last edited on
Here is your code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <iomanip>
#include <sstream>
 
using namespace std;
 
class List {
private:
	int numItems;
	int *array;
 
public:
	List(int n = 20) {
		numItems = n;
		array = new int [numItems];
	}
};

int main()
{
  //finding heap and stack from:
  List myList;
  //or List lists[5];
  //or List *special = new List(10);
}

Yes that is my code, the question is how to figure out stack and heap for each of the lines I mentioned, seperately.
I guess I still don't exactly know what the question is. What level of detail are you looking for? I'll try to be specific.

- You have an object of type List.
- This object is allocated "on the stack" on line 22.
- Specifically, sizeof(List) bytes are allocated; enough to hold the 'numItems' and 'array' (just the pointer) variables, plus implementation-defined padding.

However, inside the implementation of the constructor, more is being allocated. You call new int[numItems]. This allocates at least sizeof(int) * numItems bytes (+some bookkeeping memory) on the heap.

___________________________________

List lists[5]; does the same as the above, but 5x. So it will allocate 5 * sizeof(List) on the stack, and do 5 separate heap allocations for each dynamic array.
Last edited on
I am wondering about the size of stack and heap in bytes, there's variations to the program (i.e. lines 22-24) and I'm not sure what impact it has on the heap or how to find it in this instance. I found the sizeof (the stack) for the mylist and pointer but list lists[5] remains unknown along with heap bytes. I'm not sure on the process to find it in these cases. (I'll try out what you said though in the last 2 lines soon)

"List myList;": stack 8 bytes,
"List *special = new List(10);": stack 4 bytes,
unknown about "List lists[5];"


Last edited on
pointers are just an integer, that is an offset into memory.
if list*special is 4 bytes, then you are on a 32 bit system. A 64 bit system would have had 8 bytes there.

list lists[5] is an array on the stack. it uses sizeof(list)*5 bytes. The heap will use whatever each array location list item allocates in subsequent code.

It seems like you are making this harder than it needs to be :)
pointers take up one integer (machine word size) of stack each, and when used for dynamic memory take up sizeof(pointer's type) * (number of things allocated) on the heap.
non pointers take up sizeof(type) each: when poked into an array, you get sizeof * number of them.
objects with internal pointers work the exact same way... an instance of the object locally on the stack still takes up sizeof(type) (this includes word sized int storage for each pointer in it) and the internal pointers each store on the heap whatever you allocate to them (size of pointer type * number of items). Its the same as simple variable types in main, just has a wrapper around it.
c++ containers work like the objects, but you can't see the pointers (private members, not accessible to you).
Last edited on
Says I am wrong, I tried to do sizeof(List) * 5 bytes for stack and 5 for heap for"List lists[5];"

for
"List *special = new List(10);" I do sizeof(special) for stack which is correct, but for heap I did sizeof(special)*#allocated (which I assume is 10), but its wrong,

"List myList;", I obtained sizeof(list) for stack--correct, and then I tried sizeof(list)*sizeof(myList) for heap which is wrong.



show what isnt right? I am not sure I followed what you did, what you got, and what you expected.
List *special = new List(10);"
sizeof(special)*#allocated

It's sizeof(special) on the stack, then sizeof(List) + <whatever is allocated within List ctor> on heap.

sizeof(list)*sizeof(myList)
This is definitely not it. sizeof(List) and sizeof(some instance of a List object) are the same thing. So you're just squaring sizeof(List).
It's sizeof(List) on the stack, and <whatever is allocated within the List ctor> on the heap.

"<whatever is allocated within the List ctor>" for the heap would then be numItems * sizeof(int) + <internal bookkeeping>.
Last edited on
My objective is to obtain bytes of stack and heap for each variation of the program (program changes to have 1 line of either
"List myList;"
"List *special = new List(10);"
"List lists[5];"

I used sizeof(xxx) to get stack for most of the questions (all but 1) heap involves obscure values and allocations. Here is a word-for-word statement:

This code results in allocation of [x] bytes in stack memory and [y] bytes in heap memory.
List's constructor allocates n objects of type int. Therefore
List myList;
Consumes sizeof(myList) bytes from the stack and 20 * sizeof(int) bytes of free store. Likewise,
List lists[5];
Consumes sizeof(lists) == 5 * sizeof(List) bytes from the stack and 5 * 20 * sizeof(int) bytes of free store; finally
List *special = new List(10);
Consumes sizeof(special) bytes from the stack and sizeof(List) + 10 * sizeof(int) bytes from the free store.
Last edited on
Thanks for your help mbozzi, however I inputted the values according to the equations and the only right answer was for the "sizeof(List) + 10 * sizeof(int)" (for heap) aside from my own determinations stated earlier. list lists[5] was also completely incorrect

(although I was kinda confused by " sizeof(lists) == 5 * sizeof(List) " does this mean stack contains 5*sizeof(List) or what?)
Last edited on
According to the equations

What equations?

Does this mean stack contains 5*sizeof(List) or what?

The object lists is an array of 5 objects of type List. So its size is the same as 5 individual List objects together. That's what I mean by
sizeof(lists) == 5 * sizeof(List)

If you wanted to get technical, these figures don't imply anything about the stack or heap usage. But try not to worry about this, it's not what your professor cares about.
Last edited on
List myList;" //one list variable on the stack. stack size is sizeof(list) now.
"List *special = new List(10);" //heap has 10 lists, sizeof(list)*10.
"List lists[5];" //stack gets 5 more, total 6, lists. stack size += sizeof(list)*5

"List *special = new List(10);" //heap has 10 lists, sizeof(list)*10.
This is an example of value initialization.
https://en.cppreference.com/w/cpp/language/value_initialization
One list is created, 10 is the argument to its constructor.

To create 10 (default-initialized) lists you'd need the square brackets instead
List *special = new List[10];
https://en.cppreference.com/w/cpp/language/default_initialization
10 Lists are created, no (non-default) arguments are passed to the constructors
Last edited on
When I refer to equations, I refer to the obtaining of values of bytes. For example:

sizeof(lists) == 5 * sizeof(List) which is true, both of their values equate to exactly 40 bytes but according to the q&a, stack is not 40.
5 * 20 * sizeof(int) is == 5*20*4 (4 is the standard size of int in bytes, 8 for double but I digress)

this equates to 400 bytes allocated on the heap (or which I assume such) but is not correct.



sizeof(List) + 10 * sizeof(int) == 48 which is true and according to q&a is correct for that particular line variation.
Last edited on
One can define the replaceable allocation functions to keep track of bytes allocated with new:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#if __cplusplus >= 201703L
#  define ATTRIBUTE_NODISCARD [[nodiscard]]
#else
#  define ATTRIBUTE_NODISCARD
#endif
#include <new>
#include <cstdlib>
#include <iostream>

std::size_t bytes_allocated;

ATTRIBUTE_NODISCARD void* allocate(std::size_t n)
{
  if (n == 0) n = 1;
  bytes_allocated += n;
  if (void* result = ::malloc(n)) return result;
  bytes_allocated -= n;
  throw std::bad_alloc();
}
ATTRIBUTE_NODISCARD void* operator new   (std::size_t n) { return allocate(n); }
ATTRIBUTE_NODISCARD void* operator new[] (std::size_t n) { return allocate(n); }

void deallocate(void* ptr, std::size_t = 0) { ::free(ptr); }
void  operator delete  (void* ptr)                { deallocate(ptr);    }
void  operator delete[](void* ptr)                { deallocate(ptr);    }
void  operator delete  (void* ptr, std::size_t n) { deallocate(ptr, n); }
void  operator delete[](void* ptr, std::size_t n) { deallocate(ptr, n); }

#include <iostream>
#include <iomanip>
#include <sstream>
 
using namespace std;
 
class List {
private:
	int numItems;
	int *array;
 
public:
	List(int n = 20) {
		numItems = n;
		array = new int [numItems];
	}
};

int main()
{
  //finding heap and stack from:
  //List myList;
  List lists[5];
  //List *special = new List(10);
  
  std::cout << bytes_allocated << " bytes allocated\n"; 
}


This program outputs 400 on various online compilers and my own system, although 400 is not the only permissible output. The sizes or alignment requirements of certain types could differ, and the compiler could perform allocation elision, or dead code elimination, or various other optimizations that could affect the output. The implementation could allocate more bytes for book-keeping information, or to satisfy alignment requirements.
http://coliru.stacked-crooked.com/a/95142d8451a77dd3

The as-if rule says the compiler optimizer is not allowed to affect the observable behavior of a program. However observable effects in replaceable allocation functions are exempt in order to allow the compiler to perform allocation elision. Here "observable" has a standardese definition. The actual amount of heap memory allocated is not observable either.

Interestingly Clang 12 doesn't perform any allocation at all, although it knows that the program should/may print 400 off the bat.
https://godbolt.org/z/vK9EGbzs8
Maybe it guarantees more than the standard does:
https://eel.is/c++draft/intro.abstract#6

I'm pretty sure your professor would be satisfied with 400. If not, maybe some data types are different sizes on their system or we misunderstand the question.
Last edited on
Thanks for your help @mbozzi seems like instructor made mistakes, you were right on for everything. Not sure why this happened. Again thanks.
You're welcome! I learned quite a bit.
Topic archived. No new replies allowed.