Assuming a simple class like below and the main like below, will the class variable be stack/heap allocated depending on how the class is instantiated? OR will the class variable be allocated depending on how it is implemented?

class Foo
{
    private:
        std::string Bar;

    public:
        Foo() : Bar(std::string()) {}
};


int main()
{
    Foo* F = new Foo();  //Will Bar be allocated on the heap because of new? OR does Bar have to be std::string*

    Foo G = Foo();   //Bar will be allocated on the stack right?
}

Recommended Answers

All 6 Replies

Class members are part of a class instance. Where they live depends upon where the instance lives. If you declare an instance of a class as an automatic variable, then it is on the stack. If you allocate it with operator new, then it is on the heap. See example:

void sumFunction()
{
    SomeClass anInstance;   // On the stack
    SomeClass* pToAnInstance = new SomeClass;   // On the heap
    .
    .
    .
}

First, a bit of vocabulary. Given a class, an object of that class will contain data members and base-class objects (the instance of its base-classes), these two things are referred to as sub-objects.

So, the fundamental thing to understand here is that, from a memory perspective, an object and the collection of all its sub-objects are one and the same thing. So, if you have this simple class:

struct Class1 {
  int a;
  int b;
};

Then, an object of class Class1 has two sub-objects, i.e., two integers. In memory, an object of class Class1 is two integers. If the object is on the stack, it is two integers on the stack. If it is on the heap (free-store), it is two integers on the heap.

As for the Foo class, then, in memory, an object of that class is a std::string. If the Foo object is on the stack, so are all its sub-objects, because they are one and the same. Sub-objects are just the sub-divisions of the memory that the object occupies. So, sub-objects always reside in the same memory (stack vs. heap) as the object they are a part of.

It's that simple. There is no indirection here. When you access a data member of an object, you are not being redirected somewhere else in memory, you are merely accessing a specific part within that object. This is one of the crucial aspects of value-semantics. In reference-semantics languages (like Java/C# and many others), everything is on the heap and everything is a re-direction to somewhere else (i.e., a reference), which adds significant overhead on every single thing you do, and thus, the much slower performance.

Of course, a data member like Bar in the Foo class is of type std::string which is a dynamic array of characters, so, of course, that array of characters will be allocated on the heap (free-store / dynamic memory). But Bar as an object (containing probably a pointer to the array of chars, a size value and capacity value) is a part of the Foo object to which it belongs. And so, in this case, since Foo contains nothing else, your code is, from a memory perspective, equivalent to:

int main()
{
  std::string* F = new std::string();
  std::string G = std::string();
}

I hope this helps, sometimes it's the simplest things that are the hardest to explain.

I understood the class is on the heap by why are all the "data-members & data-functions" on the heap too if they are not allocated with new?

Can functions even be on the heap? I thought the stack pops when the function returns so where does the heap come in?

Can functions even be on the heap?

Functions do not occupy any memory on a per-object basis, only the data members. Functions are made up of executable code and occupy memory on the code-section of the program's memory. They exist in one place for the whole program, and require zero memory per object. And no, they cannot be on the heap, even if you tried, you cannot have executable code in the freestore (as far as I know, and any attempt to do so is definitely a very unusual hack).

I understood the class is on the heap by why are all the data-members on the heap too if they are not allocated with new?

I think you seem a bit confused about what the difference between the stack and the heap is. You seem to think of those two things as sort of the same thing (free-store), which is incorrect, so let me just spell that out to make sure the foundation is solid.

The stack is a static chunk of memory that is given to the program (at startup) to allow it to create local (automatic) variables within functions. We generally say that the stack grows as functions get called (entered) and shrinks when they return, which is a pretty accurate way to picture it. Think of the stack as a large static array (usually between 1Mb and 8Mb), and you start with a pointer sptr to the start of that array. You enter the main() function, and say you have an int and a double as local variables within the main() function, then you move that stack-pointer sptr forward by sizeof(int) + sizeof(double), and now you can use the memory at sptr - sizeof(int) - sizeof(double) for the int variable and the memory at sptr - sizeof(double) for the double variable. As you call another function, which in turn has local variables, it will also move the sptr pointer forward by the amount necessary (i.e., "grow the stack") to accomodate its local variables. If there are objects among those local variables, then the constructors will be called on those memory slots created on the stack. When the function returns, destructors will be called, and finally, the sptr pointer will be moved back to where it was just before the function call so that the main() function can continue as if nothing happened. So, you can see that this is very limited, but also very fast because all you do to "allocate" room on the stack is change the value of a pointer.

Side Note: If you have too deeply nested function calls (e.g., a recursion), the stack-pointer might reach the end of the stack, that's called a stack overflow, which causes an immediate (and I mean, immediate) halt of the program.

So, if the stack is grown to accomodate an object (that is, all of its sub-objects), then the sub-objects reside within that stack memory.

The heap is an entirely different (and much more flexible) type of storage (and thus, slower to allocate from). The heap acts as a memory broker between the program and the OS (which ultimately controls the system's memory). The heap is given memory from the OS (upon kernel-call requests for it) and it manages that large chunk of memory by keeping track of what is available and what is occupied (actually, it only tracks the available memory). So, allocating something with new involves requestion the heap to search for a nice spot with enough available memory, choosing that "nice spot" is far from being a trivial problem, and that's where the performance hit comes from.

So, if you request some memory from the heap in order to accomodate an object (that is, all of its sub-objects), then the sub-objects reside within that heap-allocated memory. There is no need for the sub-objects to be somehow directly involved in a new expression, the sub-objects exist where the object exists, they are a constituent part of the object. If the object is in heap-allocated memory, then its sub-objects are there too, and if the object is on the stack, then its sub-objects are there too, because they always occupy the same memory, they are one and the same.

Ahh I see. The part that confused me previously was that they all occupy the same space. I was reading some book and the author for some reason said that classes just store pointers to the location of all datamembers so I was thinking that if the datamember does not use new then it will always be on the stack and if it uses new it'll be on the heap regardless of where class itself is allocated.

I did not know they were sub-objects. I thought it was just like Java's classes. Thanks alot to both of you! Definitely cleared it up.

I was reading some book and the author for some reason said that classes just store pointers to the location of all datamembers

That's the way it is in reference-semantics languages like Java or C#. This is not true for C++ (which has value-semantics), either the author is not talking about C++ or he knows nothing about C++. In reference-semantics languages, the stack doesn't exist (abstracted away) and automatic variables don't exist either. All memory is managed by a virtual machine, so, it's all essentially heap-allocated memory, and each data member is also individually heap-allocated, and there's an extra indirection (reference) to everything you do (although sophisticated virtual machines try to optimize away some indirections and some heap-allocations). This fundamental difference leads to completely different styles of programming, so, be very careful about mixing books / personal-knowledge of Java/C# with C++, it's a bit like trying to learn to do snowboarding by taking skiing classes (or vice versa), they are kind of similar and knowing one helps for learning the other, but if you try to face forward (as you would while skiing) while on a snowboard, all you'll do is fall on your face. If you are transitioning from Java to C++, keep that in mind, and don't blame the shape of the snowboard for your falls, just learn to ride it in the direction it's meant to go.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.