From: RB on
I have the following confusions on Class creation. It appears
from macro expansion and stepping thru the framework calls
that the DocTemplate which holds the original Doc/View members
are created as nameless object instances referenced with a ptr
on the heap, correct ?
// eg:
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CFileHandlingDoc),
RUNTIME_CLASS(CMainFrame),
RUNTIME_CLASS(CFileHandlingView));
AddDocTemplate(pDocTemplate);

// So if I derive a class as say,
MyClass::MFC_BaseClassWhatever
{ int Whatever = 1;
MyClass() {}
~MyClass() {}
};
// and then create an instance of it without using new as in,
MyClass MyClassObj;
// is MyClassObj here, created on the heap or the stack ?

// And what if I create the object as a member of a class
// already created on the heap as in,

class CFileHandlingDoc : public CDocument
{
protected:
CFileHandlingDoc();
DECLARE_DYNCREATE(CFileHandlingDoc)
MyClass MyClassObj;
///------rest of class
// is MyClassObj here, created on the heap or the stack ?

// And finally am I correct in ascertaining that as long as I don't
// actually create a class (or anything ) using
WhateverType* pWhatever = new WhateverType;
// then I don't have to worry about
delete pWhatever; // in the destructor or where ever
// correct ??


From: David Lowndes on
>I have the following confusions on Class creation. It appears
>from macro expansion and stepping thru the framework calls
>that the DocTemplate which holds the original Doc/View members
>are created as nameless object instances referenced with a ptr
>on the heap, correct ?
>// eg:
>CSingleDocTemplate* pDocTemplate;
>pDocTemplate = new CSingleDocTemplate(

pDocTemplate is a local variable and the memory for CSingleDocTemplate
is allocated from the heap.

>// So if I derive a class as say,
>MyClass::MFC_BaseClassWhatever
> { int Whatever = 1;
> MyClass() {}
> ~MyClass() {}
> };
>// and then create an instance of it without using new as in,
>MyClass MyClassObj;
>// is MyClassObj here, created on the heap or the stack ?

if that line is inside a function rather than global, it's memory is
allocated from the stack.

>// And what if I create the object as a member of a class
>// already created on the heap as in,

It forms part of the class it's a member of, so it's in the same place
as the class instance (on the heap in your envisaged situation).

>// And finally am I correct in ascertaining that as long as I don't
>// actually create a class (or anything ) using
>WhateverType* pWhatever = new WhateverType;
>// then I don't have to worry about
>delete pWhatever; // in the destructor or where ever
>// correct ??

Yes.

Dave
From: Oliver Regenfelder on
Hello,

RB wrote:
> I have the following confusions on Class creation. It appears
> from macro expansion and stepping thru the framework calls
> that the DocTemplate which holds the original Doc/View members
> are created as nameless object instances referenced with a ptr
> on the heap, correct ?
> // eg:
> CSingleDocTemplate* pDocTemplate;
> pDocTemplate = new CSingleDocTemplate(
> IDR_MAINFRAME,
> RUNTIME_CLASS(CFileHandlingDoc),
> RUNTIME_CLASS(CMainFrame),
> RUNTIME_CLASS(CFileHandlingView));
> AddDocTemplate(pDocTemplate);
>
> // So if I derive a class as say,
> MyClass::MFC_BaseClassWhatever
> { int Whatever = 1;
> MyClass() {}
> ~MyClass() {}
> };
> class CFileHandlingDoc : public CDocument
> {
> protected:
> CFileHandlingDoc();
> DECLARE_DYNCREATE(CFileHandlingDoc)
> MyClass MyClassObj;
> ///------rest of class
> // is MyClassObj here, created on the heap or the stack ?

It depends on where your CFileHAndlingDoc object is created.
If the CFileHandlingDoc object is on the stack then the MyClass
object will be on the stack.

> // And finally am I correct in ascertaining that as long as I don't
> // actually create a class (or anything ) using
> WhateverType* pWhatever = new WhateverType;
> // then I don't have to worry about
> delete pWhatever; // in the destructor or where ever
> // correct ??

Yes.
If you create objects dynamically you should use smart pointers so
you don't have to think about the delete.

Best regards,

Oliver
From: Joseph M. Newcomer on
See below...
On Wed, 2 Jun 2010 11:13:05 -0400, "RB" <NoMail(a)NoSpam> wrote:

>I have the following confusions on Class creation. It appears
>from macro expansion and stepping thru the framework calls
>that the DocTemplate which holds the original Doc/View members
>are created as nameless object instances referenced with a ptr
>on the heap, correct ?
>// eg:
>CSingleDocTemplate* pDocTemplate;
>pDocTemplate = new CSingleDocTemplate(
> IDR_MAINFRAME,
> RUNTIME_CLASS(CFileHandlingDoc),
> RUNTIME_CLASS(CMainFrame),
> RUNTIME_CLASS(CFileHandlingView));
>AddDocTemplate(pDocTemplate);
****
In this case, because of the 'new' operator, this is definitely an object allocated on the
heap. The pointer to the object is allocated on the stack.
****
>
>// So if I derive a class as say,
>MyClass::MFC_BaseClassWhatever
> { int Whatever = 1;
> MyClass() {}
> ~MyClass() {}
> };
>// and then create an instance of it without using new as in,
>MyClass MyClassObj;
>// is MyClassObj here, created on the heap or the stack ?
****
I presume you mean the above appears as a local declaration in the context of a function.
In that case, the object exists on the stack and will disappear when the variable leaves
scope; the space will be reclaimed when the function exits (on function entry, space in
the local variables area is allocated for all such local variables, even if the variables
are not in scope. So consider the following

class CWhatever {
public:
int x;
int y;
};

OK, let's assume that sizeof(CWhatever) == 8 (for two 4-byte, i.e., 32-bit, int values).

Then consider the function

void func()
{
CWhatever w1;
if(test)
{
CWhatever w2;
...other code here
}
}

Then on entry, there will be 16 bytes allocated on the stack, and they will be deallocated
when the function returns. So, in effect, space for w2 exists even if the w2 variable is
not actually usable by the code because it is not in scope. So there is no allocation
done if the if-test returns true. On the other hand, consider the following class:

class COther {
public:
int * x;
int * y;
COther() { x = new int; y = new int; *x = 0; *y = 0; }
~COther() { delete x; delete y; }
:}

And consider

void func()
{
COther w1;
if(test)
{
COther w2;
... other code here
}
}

Now in this case, in Win32 sizeof(COther) == 8 (two 4-byte,that is, 32-bit, pointers)

Now, 16 bytes will be allocated on the stack when the function is entered, same as above.
But each time the variable is declared, its constructor is called, which allocates space
on the heap; this space is not reclaimed until the variable leaves scope and the
destructor is called. So in addition to the 16 bytes on the stack (two COther variables
on the stack, allocated on function entry), after the point where w1 is declared, an
additional amount of space will be consumed on the heap (depending on various conditions,
this can vary from 32 to 72 bytes for each allocated int). This space on the heap is
reclaimed when w1 goes out of scope; The space on the heap is not created until the
if-test code enters the block in which w2 is declared, and when that block exits, the
destructor for w2 is called and the heap space is reclaimed.
****
>
>// And what if I create the object as a member of a class
>// already created on the heap as in,
>
>class CFileHandlingDoc : public CDocument
> {
> protected:
> CFileHandlingDoc();
> DECLARE_DYNCREATE(CFileHandlingDoc)
> MyClass MyClassObj;
****
In this case, it is allocated wherever CFileHandlingDoc is allocated, as *part* of the
CFileHandlingDoc class; since this is a document class, this object will be allocated on
the heap, and the MyClassObj space is part of that heap object
****
> ///------rest of class
>// is MyClassObj here, created on the heap or the stack ?
****
A class which defines an object has the space for its contained object allocated in the
same place as the object itself.
****
>
>// And finally am I correct in ascertaining that as long as I don't
>// actually create a class (or anything ) using
>WhateverType* pWhatever = new WhateverType;
>// then I don't have to worry about
>delete pWhatever; // in the destructor or where ever
****
Because the object is allocated where the containing object is allocated, and it is not a
pointer to an object, there is no need to worry about the destructor. In fact, calling
the delete operator on the contained object will be erroneous; it probably won't even
compile, but if you can fool it into compiling, it will probably take some fatal error
such as an access fault (in release mode), or take an assertion failure in debug mode (and
continuing from that will probably generate an access fault)

Note that your use of the notation pWhatever says it is a pointer. Therefore, it *must*
be allocated by 'new' and *must* be explicitly freed by delete. BUt that is because it is
a pointer to an object, not an object itself.
joe
****
>// correct ??
>
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: RB on
Thanks to all of you who replied, just now getting back online.
I originally posted since I was having trouble getting a breakpoint to
hold anywhere that I could get a look at the difference between a
Global and Local instance. I later created a small console app
(shown below) where I was able to actually see the two scenrarios
being created in dissassembly.
But I'm glad I posted anyhow since you answered my confusion
and there is no way that I know of to actually find out the size of the
stack, I was only able to decipher what "appeared" to be created on
the heap.
Below is the app I experiemented with. My assembler is very rusty
but I pulled out my old book and I believe I have the // comments
correct.
-----------------------------------------------------------------
class Class
{
public:
int G;
char GString[14];

// Construction
Class()
{
G = 0xAAAAAAAA;
int ct = 0;
while(ct < 14)
{
GString[ct] = 'S';
ct++;
}
GString[ct] = '\0';
}

// Destruction
~Class()
{
}
}; // end of Class implemetation

//Global objects
Class Global;

void main(void)
{
Class Local;
}
-------now the view into the construction of each
-------starting with global object construction
5: class Class
6: {
7: public:
8: int G;
9: char GString[14];
10:
11: // Construction
12: Class() //arriving into the constructor code
004010B0 55 push ebp //save stack state again
004010B1 8B EC mov ebp,esp
004010B3 83 EC 48 sub esp,48h //allocate 48h bytes of stack
004010B6 53 push ebx //save regs
004010B7 56 push esi
004010B8 57 push edi
004010B9 51 push ecx //save offset of class on stack
004010BA 8D 7D B8 lea edi,[ebp-48h] //grab addr into edi
004010BD B9 12 00 00 00 mov ecx,12h //num of rep's
004010C2 B8 CC CC CC CC mov eax,0CCCCCCCCh //val to initialize
004010C7 F3 AB rep stos dword ptr [edi] //do the stos
004010C9 59 pop ecx //retrieve class offset addr
004010CA 89 4D FC mov dword ptr [ebp-4],ecx //put it in ebp-4
13: {
14: G = 0xAAAAAAAA;
004010CD 8B 45 FC mov eax,dword ptr [ebp-4] //mov offset in eax
004010D0 C7 00 AA AA AA AA mov dword ptr [eax],0AAAAAAAAh
// moved val into addr ptr setting in eax, Class int G has just been initialized
// to 4 bytes of Ah. However the addr value is 427D50h and the current stack
// is 12FECCh thru 12FE84h so it would appear that Class in not on the stack
// but on the heap, since is (427D50h - 12FE84h) = 3112652d or
// (2F7ECCh)bytes above current stack and the stack grows down.
-----------now the local object construction
5: class Class
6: {
7: public:
8: int G;
9: char GString[14];
10:
11: // Construction
12: Class()
004010B0 55 push ebp //save stack state
004010B1 8B EC mov ebp,esp //reset stack base
004010B3 83 EC 48 sub esp,48h //allocate 48h bytes on stack
004010B6 53 push ebx //save regs
004010B7 56 push esi
004010B8 57 push edi
004010B9 51 push ecx //save offset of class on stack
004010BA 8D 7D B8 lea edi,[ebp-48h] //loads 12FED0 in edi
004010BD B9 12 00 00 00 mov ecx,12h // mov count for rep
004010C2 B8 CC CC CC CC mov eax,0CCCCCCCCh // initializer value
004010C7 F3 AB rep stos dword ptr [edi] // initialize 12h*4= 48h bytes
004010C9 59 pop ecx // retrieve the value passed in ecx, 12FF6Ch
004010CA 89 4D FC mov dword ptr [ebp-4],ecx // put at ebp-4
13: {
14: G = 0xAAAAAAAA;
004010CD 8B 45 FC mov eax,dword ptr [ebp-4] // mov it to eax
004010D0 C7 00 AA AA AA AA mov dword ptr [eax],0AAAAAAAAh
// mov 4 bytes of Ah's this address which I now see is address of the
// class int G, and it's addr is shown to be 12FF6Ch which is probably on
// the stack and not the heap since ebp-48h is 12FED0h, which is only
// 156d bytes away.