How would I identify the stack and heap in int main?

Wondering how I can identify memory within c++ program, code is here:

https://pastebin.com/S2KMYcKV
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>

using namespace std;
 
class Date
{
public:
    Date(int mm=0, int dd=0, int yy=0)
    {
        year = yy;
        month = mm;
        day = dd;
    }

    Date(string dateString)
    {
        char temp;
        istringstream(dateString) >> month >> temp >> day >> temp >> year;
    }
 
 
   // ...
 
private:
    int day, month, year;
};
 
//class to store time and display and do increment() operation
class Time
{
public:
    Time(int hh=0, int mm=0, int ss=0)
    {
        hour = hh;
        minute = mm;
        second = ss;
    }
    Time(string timeString)
    {
        char temp;
        istringstream(timeString) >> hour >> temp >> minute >> temp >> second;
    }
 
   // ...
 
private:
    int hour, minute, second;
};
 
//composition - we used 2 objects: Date & Time objects
class DateTime
{
public:
    //another way to build DateTime object
    DateTime(Date dt, Time tt) {
        date = dt;
        time = tt;
    }
 
 // ...
 
private:
    Date date;
    Time time;
};

int main()
{
Date date("1/1/1990");
 
Time time("12:15:15");
 
DateTime *dtp = new DateTime(date, time);
 
}


Within your main function, your first two objects (Date date and Time time) are allocated on the stack.
The third object you allocate is from the "new Date(date, time)" call. This object lives on the heap. The pointer to this memory, dtp, is on allocated on the stack.

The heap memory itself should be properly cleaned up through a delete call.

1
2
3
4
5
DateTime *dtp = new DateTime(date, time);

// ...

delete dtp;


Aside from being a learning exercise, there is really no point to dynamically allocate the DateTime object here. It can just be on the stack like the other objects.
Last edited on
string & istringstream may or may not use the heap, and they use the stack as well. these are objects and inside them they can choose to allocate heap memory without your explicit knowing or actions. String specifically decides if its longer than N (usually 8 bytes, not sure on that 100%) it moves to the heap while the stream could do anything I don't know what is inside it.

you can, I suppose, check sizeof(specific object) vs sizeof(specific type)
eg
string test = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
check sizeof(test) vs sizeof(string). if its the same, the data probably went off to the heap.
I don't think that last part is correct. sizeof(string or string object) will always be a constant. It's just that for small strings they cleverly use the existing bytes to avoid allocating heap memory.
correct. they are the same, which show that the string data is off on the heap. There is no where else it could go, unless the string had an internal array of massive size, but sizeof string isnt that big.
I do not know of any way to make any kind of object have a different size from its type's sizeof. Maybe a nonstandard dynamic array intenrally? But nothing standard. The point is that a 50 or whatever byte object like string can't have 1000 letters in it without some heap...

you are right though, the test isnt very good or correct. Other objects without heap would not change their sizeof either... but they also can't change size to fit bigger data (cant hold more bytes than their sizeof).

so, let me say that less confusingly to juicy...
the container classes build into c++ all used dynamic memory if they can grow to fit any amount of data. This includes list,map,string,vector,valarray and so on.
Last edited on
Types of memory: http://www.gotw.ca/gotw/009.htm
Storage duration: https://en.cppreference.com/w/cpp/language/storage_duration

1
2
3
4
5
6
int main() {
  const char* one = "Hello";
  std::string two( "World" );
  std::vector<std::string> three{ two };
  three[0] += "!!";
}

The one, two, and three all have automatic storage duration and are allocated from stack.
The "Hello" is a constant string literal that is stored in const data section.
The two may or may not allocate dynamic memory (free store, heap) for storing a copy of value "World".
The three will allocate dynamic memory for a std::string object (that is initialized with value of 'two').

The three is in stack. The three[0] is in "heap". The "World!!" stored by three[0] is in heap too. Is it in block allocated by three[0] or within three[0]?


@jonnin: the keyword is "optimization". We know that std::string is a class. We know that it has a char* member. On most implementations the string object is larger than a pointer, so it has some other data members too. It can have a small array of char. The pointer could point to that, rather than to dynamically allocated array.

Yes, if all your strings are long, then the array member would not be used at all but the waste of space would be relatively small.
Yes, there will be some extra logic for juggling between member and dynamic.
However, if all strings are small enough to fit into the member array, then no dynamic allocations are needed at all.
Is such optimization worth the effort? The authors of a Standard Library implementation make that call.

1
2
// How many allocations?
std::vector<std::string> four( 1'000'000, two );

If string has the optimization (and "World" fits in it), then only one: vector allocates array for million strings.
If not, then vector allocates array for million strings and each string allocates an array for its data. 1'000'001 allocations.
For MS VS, the small buffer is 15 bytes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <string>
#include <iostream>
#include <iomanip>

int main()
{
	std::string s;

	std::cout << "sb " << std::hex << (void *)s.data() << "  " << std::dec << s.capacity() << '\n';

	for (const auto sb {s.data()}; s.data() == sb; s += ' ');

	std::cout << " b " << std::hex << (void *)s.data() << "  " << std::dec << s.size() - 1 << '\n';
}



sb 00000000001DF7A0  15
 b 00000000004157D0  15


This shows that the sb is on the stack and when it is exceeded, heap memory is used.
Topic archived. No new replies allowed.