AndreStony
AndreStony

Reputation: 87

Why does my object appear to be on the heap without using `new`?

I'm starting to learn the topic of dynamic memory allocation.

I have the following code:

#include <iostream>
#include "A.h"
#include "B.h"

using namespace std;

int main() {

   /* Both objects on Stack */

   A classAStack;
   B classBStack;

   /* Both objects on Heap*/
   //  A *classAHeap = new A();
   //  B *classBHeap = new B();

   /* A objects on Heap B ???*/
   A *classAHeap = new A();

   return 0;
}

#ifndef A_H_
#define A_H_

#include <iostream>
#include "B.h"

class A {
public:
   A();
   virtual ~A();

public:
   B b;
};

#endif /* A_H_ */

#include "A.h"

A::A() {
   std::cout <<"Constructor A called" << std::endl;
}

A::~A() {
}

#ifndef B_H_  
#define B_H_

#include <iostream>

class B {
public:
  B();
  virtual ~B();
};

#endif /* B_H_ */

#include "B.h"

B::B() {
  std::cout <<"Constructor B called" << std::endl;
}

B::~B() {
}

The output of the Debugger is:

Temporary breakpoint 6, main () at ../src/HeapStackTest02.cpp:18
18    A classAStack;

Breakpoint 4, B::B (this=0x23aa58) at ../src/B.cpp:12
12    std::cout <<"Constructor B called" << std::endl;

Breakpoint 5, A::A (this=0x23aa50) at ../src/A.cpp:13
13    std::cout <<"Constructor A called" << std::endl;

Breakpoint 4, B::B (this=0x23aa40) at ../src/B.cpp:12
12    std::cout <<"Constructor B called" << std::endl;

Breakpoint 4, B::B (this=0x60004b048) at ../src/B.cpp:12
12    std::cout <<"Constructor B called" << std::endl;

Breakpoint 5, A::A (this=0x60004b040) at ../src/A.cpp:13
13    std::cout <<"Constructor A called" << std::endl;

Breakpoint 1, main () at ../src/HeapStackTest02.cpp:30
30    return 0;

To my question:

Where is the member-variable b of class A?

If I look at the address in section 0x23a, it seems to be the stack, and the section 0x6000 seems to be the heap.

I'm working on a Windows 64-bit system.

Why the member-variable b is also on the heap, without the new operator being called?

Upvotes: 3

Views: 598

Answers (3)

Alexey Polyudov
Alexey Polyudov

Reputation: 164

To answer the question, let's start with finding out how many instances of type B do we have. The answer is 3.

One instance is member b of type A (on stack). Another one is instance of B on stack, and the third one is the instance of member b of type A on heap.

Why is it on heap? It is there, because you created instance of type A on heap, and instance of A has instance of B as member.

So one of 3 instances of B is on heap, and the other 2 are on stack.

Upvotes: 3

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385108

The member is b is part of the object that you dynamically allocated, so it is part of that dynamic allocation and is at the same location in memory.

If the members were not part of the object, what would be left? What would you have dynamic allocated?

This is why you should avoid the terminology "on the heap" when you see new. It is not just things that you new that are "on the heap". No, new dynamically allocates an object and everything that the object directly contains. Any mental association between how you wrote an object's declaration and whether it is "on the heap" or "on the stack" is doomed to failure.

The only reliable way to determine an object's storage duration is to know its history; the only reliable way to determine an object's storage location is to not bother because you don't need to.

Upvotes: 4

sabee
sabee

Reputation: 217

Consider this:

#include <iostream>
#include <string>

class B {
public:
    int64_t x = 42;
    int64_t y = 7;
};

class A1 {
public:
    B b;
};

class A2 {
public:
    A2() { b = new B(); }
    B* b;
    ~A2() { delete b; }
};

int main() {
    std::cout << sizeof(A1) << std::endl;   // prints 16
    std::cout << sizeof(A2) << std::endl;   // prints 8

    // Section (2)
    A1 a1;  // Instance of A1 and B are on the stack
    A2 a2;  // Instance of A2 is on the stack. B is on the heap.

    A1* a3 = new A1();
    std::cout << a3 == &(a3->b) << std:: endl;  // prints true

    A2* a4 = new A2();
    std::cout << a4 == a4->b << std::endl;  // prints false

    return 0;
}   

Upvotes: 1

Related Questions