7

Take the following:

A a;

class B; // No content for brevity

class A
{
public:

    A()
    {
         b.SetTitle("hi");
    }

private:

    B b;

}

int main()
{
    return 0;
}

The question here is if b which is declared inside A is declared on the heap or on the stack.

If on the heap, does this mean it is automatically deleted or must i also delete this too?

Side question:

This is what i was originally doing but thought i was being a bit stupid as i had to keep declaring everything as new everywhere.. if the above is on the stack, i guess it wasn't so stupid right?

A a;

class B; // No content for brevity

class A
{
public:

    A()
    {
         this->b( new B() ); // I don't have C++ 14 :( so i can't do make_unique
         b->SetTitle("hi");
    }

private:

    unique_ptr<B> b;

}

int main()
{
    return 0;
}
Jimmyt1988
  • 20,466
  • 41
  • 133
  • 233
  • 4
    If you use `new`, the memory will be on the heap. If it is in a function, not declared as static, on the stack. If it is declared as static in a function or as global to a file or program global, it will be declared in another memory section. If the instance is constant it could be allocated in a read-only segment. OMG, there are more than two areas of memory???? – Thomas Matthews May 09 '15 at 23:07
  • 7
    The flagrant errors made by two answerers below are a perfect example of using "stack" and "heap" terminology when you should not. Care about storage duration, not implementation-specific physical storage locations. – Lightness Races in Orbit May 09 '15 at 23:13
  • 1
    In the embedded systems world, memory locations may be placed in different physical locations. For example, we could place stack in one area of memory (like the memory on the System On A Chip), we could place heap (if we use it) in slower cheaper SRAM. Constant literals, like text, could be placed in Flash or ROM. Some static constant variables may even be placed with the executable. Don't worry where the variables are located. Worry about their size, how they are passed and their lifetimes. – Thomas Matthews May 09 '15 at 23:25
  • Some might say worrying about their size and lifetime leads to the the requirement of worrying where you put them. For example, I know that my class A (in my real app) is going to have a lot of large classes stored inside it as it is the hub of my whole application... In this case, I need to be sure i'm not storing anthing on the stack... right?.. as im gnna overflow. – Jimmyt1988 May 09 '15 at 23:30
  • 1
    Here's a tip: Until you understand how to use allocation and when you need to free things and when you don't, don't even think about the stack/heap distinction. – David Schwartz May 09 '15 at 23:33

2 Answers2

10

It still could be either or even (as Thomas Matthews points out below) in a fixed memory block. In this case you can think of it as "inside of A". If you put A on the heap it's on the heap. If you allocate "A" at the top of a function, say, it's on the stack (but inside of A).

Written like this it is a part of A and its lifetime is tied to A. You only need to worry about managing A.

Alfred Rossi
  • 1,942
  • 15
  • 19
  • 3
    BTW, there are other areas of memory besides stack and heap. For example, if I declare a global instance of `A`, where does it reside? *Hint: not on stack, not on heap.* – Thomas Matthews May 09 '15 at 23:10
  • 1) Do i in this case need to worry about stack overflows (my real life class is going to need a lot of stuff inside)... 2) if 1 is yes and i should make unique_ptrs... then should i also make primitive int and string types unique_ptrs in the class so that i never risk overflowing the stack? – Jimmyt1988 May 09 '15 at 23:17
  • 1
    Pass large variables by reference. Declare huge variables as static or in file local scope. If they don't fit there, try the heap. – Thomas Matthews May 09 '15 at 23:20
0

Code Examples: Stack Vs Heap.

// Not a proper class but used for demonstration purposes
class SomeClass {
private:
    int x;
    int* ptr;

public:        
    SomeClass() {
        // Both On x and ptr are on the stack when this constructor is defined and used.
        x = 10; 
        ptr = &x;
    } 

    SomeClass() { 
        // x is on the stack but ptr is on the heap and delete needs to be called to release the memory.
        x = 10;
        ptr = new int;
    }          
};

void someOtherFunction() {
    SomeClass a;  // on the stack relative to this function
    SomeClass* ptr = nullptr; // ptr is on the stack and is initialize to null.
    ptr = &a; // Still on the stack and ptr stores the address of (a).  

    ptr = new SomeClass(); // Now ptr lives on the heap and delete needs to be called to release its memory.         
}

Initially (ptr) does not have an address stored within in it because we initialized it to nullptr upon declaring it. It is stored on the stack, the address of (ptr) at this time has an address that is part of the stack memory addressing. Now we assign the address of (a) to (ptr); (ptr) is still on the stack, (a) is on the stack and the address of (a) is stored into (ptr).

Once we set (ptr) = new SomeClass() it is at this point that the compiler sets aside memory with the size of this class object and saves a random address from the heap into (ptr). (ptr) itself is still on the stack of this function but the memory address that (ptr) now stores is from the heap. The contents of (ptr) is accessible outside the scope of this function but needs to be return either through this functions return type or one of its parameters by reference.

Another words the address of (ptr) does not change within this function, it remains the same because the variable (ptr) itself still lives on the stack, it is what this pointer variable holds that changes from a stack memory address to a heap memory address once new is used.

To demonstrate this run this code in main() and look at the results; this still applies within other functions and class-struct objects.

#include <iostream> 

int main() {
    int a = 10;
    int* ptr = nullptr;
    std::cout << "Memory Address that ptr is pointing to: " << ptr << std::endl;
    std::cout << "Memory Address of ptr: " << &ptr << std::endl;
    // std::cout << "What is stored in the variable at this memory address: " << *ptr << std::endl; // This can not be called program will crash,
    // ptr can not be dereferenced for it is not pointing to anything
    std::cout << std::endl;

    ptr = &a;
    std::cout << "Memory Address that ptr is pointing to: " << ptr << std::endl;
    std::cout << "Memory Address of ptr: " << &ptr << std::endl;
    std::cout << "What is stored in the variable at this memory address: " << *ptr << std::endl;
    std::cout << std::endl;

    ptr = new int;
    *ptr = 12;
    std::cout << "Memory Address that ptr is pointing to: " << ptr << std::endl;
    std::cout << "Memory Address of ptr: " << &ptr << std::endl;
    std::cout << "What is stored in the variable at this memory address: " << *ptr << std::endl;
    std::cout << std::endl;

    delete ptr;

    return 0;
}

As you can see the memory address of (ptr) does not change, what does change is the memory address that is stored within (ptr). Now the address of (ptr) can change if you use new on another pointer that is pointing to (ptr).

Now when you call new on a class type and you store the heap memory address into a pointer of that type, the memory address is where the class object lives so in this case anything that belongs to this class is on the heap.


Globals & Static Variables:

  • Globals - Globals are listed in the (program file namespace)* and are accessible anywhere in the file they are declared and have the life time of the application.

  • Static local variables are like global variables except they are only accessible in the function they are declared and are only initialized once per application runtime. They have the life time of the application.

  • Static member variables to a class behave similar as regular static variables but they do not have the (this) pointer associated to them. They are visible to the function that declares them, they are initialized once per application runtime, and they have the life time of either the application run time or until there exists no more instances of that class object.

(*) Do not know the technical name but using program file namespace makes sense according to how global variables and their memory behave. - I rarely use global variables!


Here are some links for references.


Community
  • 1
  • 1
Francis Cugler
  • 7,788
  • 2
  • 28
  • 59