Class members and explicit stack/heap allocation - c++

Let's say we have 4 classes as follows:
class A
{
public:
A(void) : m_B()
{
}
private:
B m_B;
}
class B
{
public:
B(void)
{
m_i = 1;
}
private:
int m_i;
}
class C
{
public:
C(void)
{
m_D = new D();
}
~C(void)
{
delete m_D;
}
private:
D *m_D;
}
class D
{
public:
D(void)
{
m_i = 1;
}
private:
int m_i;
}
Lets say there are 4 cases:
case 1: A externally allocated on the stack, B internally allocated on the stack
A myA1;
case 2: A externally allocated on the heap, B internally allocated on the stack
A *myA2 = new A();
case 3: C externally allocated on the stack, D internally allocated on the heap
C myC1;
case 4: C externally allocated on the heap, D internally allocated on the heap
C *myC2 = new C();
What goes on in each of these cases? For example, in case 2, I understand the pointer myA2 is allocated on the stack, the A object exists in the heap, but what about the m_B attribute? I assume space on the heap allocated for it as well because it wouldn't make sense for an object to exist in heap space and then it's attribute goes out of scope. If this is true then does that mean the external heap allocation overrides the internal stack allocation?
What about case 3, myC1 is allocated on the stack, however m_D is allocated on the heap. What happens here? Are the two parts split across memory? If I removed the 'delete m_D' from the destructor and myC1 went out of scope, would there be a memory leak for the space allocated on the heap for m_D?
If there are any tutorials/articles that go over this in detail I would love a link.

I think that you are confusing "stack/heap allocation" and "automatic variable".
Automatic variables are automatically destroyed when going out of context.
Stack allocation is the fact that the memory is allocated on the execution stack. And variable allocated on the stack are automatic variables.
Also, members are automatic variables whose destructors get called when its owner is destroyed. In the case of pointers, they are destroyed but not the underlying object, you have to explicitly call delete. To make sure that the underlying object is destroyed you have to use smart or unique pointers.
To put it another way: variables/members that you have to call delete on, are not automatic variables.
Lastly, member of a class are allocated on the same memory segment of the its owner.
In you code:
A.m_B is an automatic variable. If A is on the stack so is B and if A is on the heap so is B.
B.m_i and D.m_i are an automatic variables and will be allocated on the same memory segment of their owner
The pointer C.m_D is an automatic variable, but the pointed object of type D is not, you have to explicitly call delete on the pointer to delete the underlying object. So, the pointer C.m_D is allocated on the same memory segment, but not the underlying objet. It's cleary allocated by new and will be on the heap.
So:
Case 1: Everything is on the stack and automatic (ie: destroyed automatically).
Case 2: myA2 is on the heap and not automatic (you have to delete myA2). Its member m_B2 is an automatic variable that will be destroyed when myA2 is destroyed. Also since myA2 is on the heap, m_B, like any member of a class, is in the same memory space the heap too.
Case 3: myC1 is on the stack and is an automatic variable, The pointer to m_D is on the stack too, but not the object pointed by m_D which is allocated by new on the heap.
Case 4: Same as case3 but myC2 is on the heap and is not automatic. So you have to delete myC2 (which will delete m_D).

Case 1: everything on the "stack" (automatic storage). Resources are released as you exit scope.
Case 2: myA2 is on the "heap", so is it's m_B, and you only have to worry about releasing the resources taken up by myA2. it's m_B will be destructed automatically when myA2 is.
Case 3: myC1 is on the stack, it's m_D points to a D on the heap, but the C destructor takes care of deleting it, so as myC1 goes out of scope, all dynamically allocated resources are cleared.
Case 4: myC2 dynamically allocated, to it must be deleted to release resources taken by it. Deleting it will call it's constructor which in turn will take care of it's m_D, as in case 3.
I am not sure about articles, I am sure there are plenty around. But I suggest reading some good C++ books

Your object is a piece of organised memory. Object does not allocate it's members on the stack, it just consists of it's members.
Case 2: the whole object exists in the heap, this means that all it's members lie in the heap.
Case 3: the whole object exists on the stack. The trick is that it's not D class instance who is member of myC1, but pointer-to-B is physically member of myC1. So member of myC1 lies on stack and points to some D instance that lies in the heap.

Related

Does my C++ variable live on the stack or the heap?

This is my first question on stack overflow. Apologies if this is a "dumb" question, but I'm currently learning C++, and I'm a little confused by something. As I understand it, in the code below, the variable "myVariable" is declared on the heap but instantiated in the constructor on the stack. So where does it "live" - on the heap or the stack?
class MyClass{
int _myVariable;
MyClass(int i){
_myVariable = i;
}
}
The member variable is allocated according to how class is instantiated.
void example() {
MyClass a{17}; // This allocates memory on stack
MyClass *b = new MyClass(17); // This allocates memory on heap
}
"Stack" and "Heap" are implementation details. The C++ standard defines Automatic Storage and Dynamic Storage.
The most common implementations for the storage of variables are stack and heap, respectively.
The new operator makes an object live on the dynamic storage:
MyClass* mc = new MyClass(14);.
Note how we now need to use a pointer to access it.
With automatic storage, we can omit the pointer semantics:
MyClass mc = MyClass(14); // constructs an object on the automatic storage.
The object lifetime is managed - you've guessed - automatically. More precisely until the end of the scope.
With dynamically allocated objects, you have to manage the lifetime of the objects yourself.
There are cases where you can't use automatic storage: Namely polymorphism.
If MyClass is polymorphic (that means, it has virtual functions), you can't put it into the automatic storage since the compiler needs to know the size of an object. Since with polymorphism, the size of the pointed-to object can change at runtime it's not possible to create it on the automatic storage.
MyClass c = MyClass2(); //Object Slicing
c.foo(); // calls MyClass::foo()
MyClass* cc = new MyClass2(); //No Object Slicing
cc->foo(); // calls MyClass2::foo();
There are helper classes that take away the responsibility to clean up your memory:
unique_ptr and shared_ptr (although the latter is used rarely).
In the given code, nothing is allocated, you have a mere class declaration.
It is contradictory (and wrong) that "myVariable" is declared on the heap while instantiated in the constructor on the stack.
A simple constructor like yours does no allocation, it just assigns value upon creation of a class instance. Constructors do not allocate the instance, destructors do not deallocate it.
The allocation being done on the heap or on the stack will depend on how you use the class (as a plain variable or with a pointer).
It depends on where does the object live. If the actual object is on the heap the variable also lives on the heap. If the object lives on the stack the variable also lives on the stack.
Look at this example:
MyClass myObject = MyClass(5); // myObject lives on the stack and thus the variable i for myObject also lives on the stack
MyClass* newObject = new MyClass(5); // newObject is allocated on the heap and the variable i for newObject lives on the heap
delete newObject; // since newObject is created using new we must free the memory after use

The difference between a destructor and 'delete'

What is the difference between the destruction of an object and deletion in C++? In OOP, when an object goes out of the scope, the destructor is called, and when dynamically allocating memory we have to use the delete keyword inside the destructor. So what does it mean for an object to be destroyed or deleted?
A destructor is a special method for a class. It is called whenever an object goes out of scope, or someone calls it explicitly.
An example where an objects destructor is called, but no delete:
struct MyObject
{
MyObject() { std::cout << "default constructor"; }
~MyObject() { std::cout << "destructor"; }
void doWork() {};
}
int main()
{
{
MyObject object; //constructor is called and memory allocated for the object on the stack
object.doWork();
} //at the end of scope, the destructor of MyObject is called, and the stack memory is "released"
// object is not longer available and stack memory is free
}
An example when scope does not help you:
int main()
{
{
MyObject* object_ptr = new MyObject; //constructor is called and memory allocated on the heap. The pointer_ptr object
object_ptr->doWork();
} //at the end of scope the object_ptr is removed from the stack, but the destructor for the MyObject is not called!
// object_ptr is no longer available.
}
For the above example, we have an issue with the dynamically allocated memory. We explicitly call the destructor of the object we are pointing to by calling delete (and freeing the memory where MyObject is residing!):
int main()
{
{
MyObject* object_ptr = new MyObject; //constructor is called and memory allocated on the heap. The pointer_ptr object
object_ptr->doWork();
delete object_ptr; // destructor of MyObject is called and memory freed.
// object_ptr is still usable here, but it is pointing at an destroyed object, so don't use it! (unless you redirect it)
}
}
So delete is for managing the dynamic memory, but the destructor is a method of the class itself, which is always called when the object is getting freed from the memory (stack or heap). The destructor is called when freeing the memory for the object, so that if the object itself handles memory, is has time to release that memory. That's why smart pointers are good:
int main()
{
{
std::unique_ptr<MyObject> object_ptr = std::make_unique<MyObject>(); //constructor is called and memory allocated on the heap. The pointer_ptr object
object_ptr->doWork();
} //destructor for std::unique_ptr<MyObject> is called, which in turn calls delete on the object it is pointing at, which calls the destructor of that object!
}
There are multiple ways for memory allocation some of them are:
Automatic memory allocation :
In this case ,the variables defined inside a scope ,for example functions, are automatic allocated, and is usually stored on the stack. You have a limited control over the lifetime of this memory. E.g: automatic variables in a function are only there until the function finishes, then when going out of that scope, their destructors are called automatically i.e. you must not call delete to free the memory reserved for that object.
Dynamic memory allocation :
In this case , the variables defined inside a scope ,for example functions, are dynamically allocated. You control the size and the lifetime of these memory locations. If you don't free the reserved memory (delete it), the allocated memory is still valid and accessible, even though the function terminated (went out of scope) and in this case you'll have memory leakage, which may cause the program to crash. So the object should be delete explicitly which in turn will call the destructor for that object.
In the same way that a constructor is only part of the process of creating an object, invoking the destructor is just part of the process of destroying an object. It is a place where special clean-up code can go, like closing file handles or destroying other, indirectly-owned objects.
delete is the way you trigger the deletion of a dynamically allocated object. Other types of object are deleted automatically when they go out of scope. This keyword will clean up memory and more abstractly end the object's lifetime so that the compiler knows it doesn't conceptually "exist" any more.
You generally don't call the destructor manually, as it is usually insufficient for safely ending the lifetime of an object on its own. However, doing so is useful when you're taking super-fine-grained control over objects' existences, with (for example) placement new: then, it can be sufficient. But this is a special case.
When an object is destroyed it's destructor is called. A pointer to a dynamically allocated memory can be deleted, objects themselves can't be deleted (unless you think of a pointer as a kind of object).
Either of these actions can have knock on effects that cause the other action to happen (or more instances of the same action). For instance if you delete a pointer to an object, then the objects destructor will be called (if it has one) and it's destructor may cause other pointers to be deleted and other objects to be destroyed.
Basically destructor is about the death of objects and deletion is about the freeing of dynamically allocated memory, but the two actions are often intertwined.

Class members memory allocation

My question is mostly theoretical. Suppose we have a class
class A{
private:
int * a;
int b;
private:
A(){
a = new int[100];
b = 100;
}
~A(){
delete [] a;
}
}
As far as I know if we create object of type A dynamically (A * a = new A()) the memory for this object will allocate in heap and if I use (A a) it will be created on stack (A a). In the case when object is created on stack memory for variable a will allocated on heap and in case when we allocated object on heap memory for object b will be allocated on stack. First question for me to be sure: am I right?
And second question would it be more efficient to store all members of class in heap memory or stack memory eg?
class A{
private:
int * a;
int * b;
private:
A(){
a = new int[100];
b = new int(100);
}
~A(){
delete [] a;
delete b;
}
}
When I said efficient I mean that all data about class member will be storing near each other in memory in heap or stack (actually I'm not sure that is correct that they will be storing near each other).
First off there is no heap or stack in C++. Instead we have automatic storage duration and dynamic storage duration. A object with automatic storage duration is a scoped object. When it goes out of scope it is automatically cleaned up. An object with dynamic storage duration on the other hand is not bound by its scope. Its lifetime only ends when it is explicitly ended by the program (generally this means calling delete).
Now in A you have one object stored with automatic storage duration , b, and one with dynamic storage duration ,a. This means that b will live wherever the A instance lives. a also lives within the A instance but the memory it points to will reside somewhere in memory but we do not know where. When the instance is destroyed b will automatically be cleaned up but a will required special handling in the destructor otherwise the memory will leak. You can visualize it like
A
+------+ +----------+
| a->+---| 100 ints |
| b | +----------+
+------+
As far as efficiency goes as Some programmer dude mentioned you should not really worry about that. You should use the types that you fell is right for the job. Once you have it up and running then you can profile it to find where the bottle neck is. If you see too many cache misses because of using pointers then you can look at trying to localize the data to the class itself.
I would also like to mention then if you find yourself writting some_type* name = new/new[] then you should consider using a std:unique_ptr<some_type>/std:unique_ptr<some_type[]> or std::vector<some_type>.
No, you are not exactly correct.
a and b are variables inside your object.
They both extends the size of your class - at least by the size of sizeof(int*).
Depending of the way you constructed your object, the memory for this variables is allocated on stack or heap as you already mentioned:
new A/int/etc allocates memory on heap
A/int/etc. var allocates memory on stack
The thing you miss is that your data allocated in constructor
a = new int[100];
is not a part of your class object. It is some external data. In your class object you have only a int* member (with a size of 4-8 bytes, depending on architecture) that points to this data.
First of all the downside to the member raw pointers (for ex. MyClass) is it forces to #include the header where MyClass is declared. This can lead to slow compilation. To solve you can use smart pointers with forward declarations.
And second question would it be more efficient to store all members of class in heap memory or stack memory eg?
Typically best to use pointer only when necessary. You should generally declare the members as values in class. It will be local, there will be less chance for errors, fewer allocations, ultimately fewer things that could go wrong, and the compiler can always know it is there at a specified offset so... it helps optimization and binary reduction at a few levels.

object created in function, is it saved on stack or on heap?

I am using c++ specifically:
when I create an object in a function, will this object be saved on the stack or on the heap?
reason I am asking is since I need to save a pointer to an object, and the only place the object can be created is within functions, so if I have a pointer to that object and the method finishes, the pointer might be pointing to garbage after.
--> if I add a pointer to the object to a list (which is a member of the class) and then the method finishes I might have the element in the list pointing to garbage.
so again - when the object is created in a method, is it saved on the stack (where it will be irrelevant after the function ends) or is it saved on the heap (therefore I can point to it without causing any issues..)?
example:
class blah{
private:
list<*blee> b;
public:
void addBlee() {
blee b;
blee* bp = &b;
list.push_front(bp);
}
}
you can ignore syntax issues -- the above is just to understand the concept and dilemma...
Thanks all!
Keep in mind following thing: the object is NEVER created in the heap (more correctly called 'dynamic storage' in C++) unless explicitly allocated on the heap using new operator or malloc variant.
Everything else is either stack/register (which in C++ should be called 'automatic storage') or a a statically allocated variable. An example of statically allocated variables are global variables in your program, variables local to the function which are declared static or static data members of classess.
You also need to very clear disntguish between a pointer and the object itself. In the following single line:
void foo() {
int* i = new int(42);
}
int is allocated dynamically (on the heap), while pointer to that allocated int has an automatic storage (stack or register). As a result, once foo() exits, the pointer is obliterated, but the dynamically allocated object remains without any means to access it. This is called classic memory leak.
Heap is the segment where dynamic memory allocation usually takes place so when ever you explicitly allocate memory to anything in a program you have given it memory from the heap segment.
Obj yo = new Obj; //something like this.
Stack is the another segment where automatic variables are stored, along with information that is saved each time a function is called.
Like when we declare:
*int* variable;
It will be on the stack and its validity is only till a particular function exits, whereas variables, objects etc on the heap remain there till main() finishes.
void addBlee() {
blee b; // this is created on the stack
blee* bp = &b;
list.push_front(bp); // this is a pointer to that object
} // after this brace b no longer exists, hence you have a dangling pointer
Do this instead:
list.push_front(new blee); // this is created on the heap and
// therefore it's lifetime is until you call
// delete on it`

Are data members allocated in the same memory space as their objects in C++?

Say I've got a class like this:
class Test
{
int x;
SomeClass s;
}
And I instantiate it like this:
Test* t = new Test;
Is x on the stack, or the heap? What about s?
Test a;
Test *t = new Test;
a, and all its members, are on the stack.
The object pointed to by t, and all its members, are on the heap.
The pointer t is on the stack.
Each time you "instantiate" an object/symbol using a new (we are speaking C++ here), a new memory zone will be allocated for this object. If not, it will be put on the "local" memory zone.
The problem is that I have no standard definition for "local" memory zone.
An example
This means that, for example:
struct A
{
A()
{
c = new C() ;
}
B b ;
C * c ;
}
void doSomething()
{
A aa00 ;
A * aa01 = new A() ;
}
The object aa00 is allocated on the stack.
As aa00::b is allocated on a "local" memory according to aa00, aa00::b is allocated inside the memory range allocated by the new aa00 instruction. Thus, aa00::b is also allocated on stack.
But aa00::c is a pointer, allocated with new, so the object designed by aa00::c is on the heap.
Now, the tricky example: aa01 is allocated via a new, and as such, on the heap.
In that case, as aa01::b is allocated on a "local" memory according to aa01, aa01::b is allocated inside the memory range allocated by the new aa01 instruction. Thus, aa01::b is on the heap, "inside" the memory already allocated for aa01.
As aa01::c is a pointer, allocated with new, the object designed by aa01::c is on the heap, in another memory range than the one allocated for aa01.
Conclusion
So, the point of the game is:
1 - What's the "local" memory of the studied object: Stack of Heap?
2 - if the object is allocated through new, then it is outside this local memory, i.e., it is elsewhere on the heap
3 - if the object is allocated "without new", then it is inside the local memory.
4 - If the "local" memory is on the stack, then the object allocated without new is on the stack, too.
5 - If the "local" memory is on the heap, then the object allocated without new is on the heap, too, but still inside the local memory.
Sorry, I have no better vocabulary to express those concepts.
Since you've used new, it's all on the heap, stored [more or less] contiguously in t's memory area.
t is on the stack. The object at *t is on the heap. It contains an int and a SomeClass object next to each other in a unit.
Since you're using new, you're allocating your object on the heap. Consequently, every members of the Test pointed by t are on the heap too.
class MyClass {
int i;
MyInnerClass m;
MyInnerClass *p = new MyInnerClass();
}
MyClass a;
MyClass *b = new MyClass();
a is on the stack; its members a.i and a.m (including any members of a.m) and a.p (the pointer, not the object it points to) are part of it and so also on the stack.
The object pointed to by a.p is on the heap.
The object pointed to by b is on the heap, including all its members; and so is the object pointed to by b.p.