Actually, neither statement says anything about heap or stack. The code
Object o;
creates one of the following, depending on its context:
This means that the storage location is determined by the context in which the object is defined. In addition, the C++ standard does not talk about stack vs heap storage. Instead, it talks about storage duration, which can be either automatic, dynamic, static or thread-local. However, most implementations implement automatic storage via the call stack, and dynamic storage via the heap.
Local variables, which have automatic storage, are thus created on the stack. Static (and thread-local) objects are generally allocated in their own memory regions, neither on the stack nor on the heap. And member variables are allocated wherever the object they belong to is allocated. They have their containing object’s storage duration.
To illustrate this with an example:
struct Foo {
Object o;
};
Foo foo;
int main() {
Foo f;
Foo* p = new Foo;
Foo* pf = &f;
}
Now where is the object Foo::o
(that is, the subobject o
of an object of class Foo
) created? It depends:
foo.o
has static storage because foo
has static storage, and therefore lives neither on the stack nor on the heap.f.o
has automatic storage since f
has automatic storage (= it lives on the stack).p->o
has dynamic storage since *p
has dynamic storage (= it lives on the heap).pf->o
is the same object as f.o
because pf
points to f
.In fact, both p
and pf
in the above have automatic storage. A pointer’s storage is indistinguishable from any other object’s, it is determined by context. Furthermore, the initialising expression has no effect on the pointer storage.
The pointee (= what the pointer points to) is a completely different matter, and could refer to any kind of storage: *p
is dynamic, whereas *pf
is automatic.