Solved

new operator

Posted on 1998-05-06
10
218 Views
Last Modified: 2010-04-10
Hi,
I'm a little unsure about the 'new' operator.  I've used it a few times but I'm not sure whether I'm using it properly.  My main problem with it is that it seems like it should be used in certain circumstances (when a member variable should not be used).
An example is a CDC*.  I recently got one (without using new) in a function to initialize a combo box (font, etc).  I figured that after I used the DC I should release it.  When I releases the DC all of the changes I made were gone and the box went back to it's default (kindof makes sense), so I held on to the DC and never released it.  No mem leaks, worked fine.

Next, I decided it might be good to keep it around for the duration of my class.  Made the CDC* as a class member and my program wouldn't even start (got an error).  This doesn't really make sense to me.

Lastly I tried to use the new operator to create the DC.  This is the part I'm having trouble understanding.
If I create a new CDC object using the new operator in a member function, how do you delete (free) the memory you allocated after the function goes out of scope?
Right now I have a member void* and make it point to the new CDC*.  On class' destruct I delete the void* (in turn deleting the DC*?).  When I debug, I get no mem leaks but the wait cursor is a bit slow to dissappear when I stop debugging (kindof like it's collecting memory leaks).  Am I deleting the CDC* through the void*?

example:
------------------------------------------------------------------------------
class MyClass : public SomeClass
{
//...
void SomeFunc();
void* mp_DC;
};
------------------------------------------------------------------------------
void MyClass::SomeFunc()
{
CDC* pDC = new CDC;
mp_DC = pDC;
//...
}
MYClass::~MyClass()
{
delete mp_DC;   // Wont let me delete what mp_DC is pointing to:   delete *mp_DC;  which would make sense
}

Is there a proper, better way to use the new operator?
Am I using it right?
Is the DC getting deleted through the void*?

Thanks in advance
0
Comment
Question by:bod_1
  • 7
  • 3
10 Comments
 
LVL 22

Accepted Solution

by:
nietod earned 20 total points
ID: 1173637
First of all you almost never want to use a void * when dealing with objects.  If you do

void *pointer = new someclass;

the object created is initialized with its constructor.  Which is a good thing.  But when you delete it doesn't know it is pointing to an object so it doesn't call the destructor.

delete pointer;

sometimes this is harmless.  Often it causes memory leaks and evenworse problems.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1173638
Next issue.  You don't want to hang onto DC's.  DCs use a lot of windows' memory and resources.  (this isn't as big a problem as it was in windows 3.1, but windows is still designed as if it were a problem) so windows only has 5 DCs that must be shared among all applications.  (it creates other DCs for windows that have class specific DCs, but this is rare).  If you hold onto a DC there is one less for others (even your own application) to use.  Once there are no avaialble DC's most windows will not be able to repaint and the screen becomes a mess!  (It doesn't crash though)

If you get a DC, use it as quickly as possible and then git rid of it.  You should not need to hold onto the DC to keep the window appearing correctly.  So something else was going on.  Note however, that each time you get the DC you need to set it the "drawing values" you want.  That is, each time you get it you will need to set the pen, the font, the colors, etc.  You can't just set it the first time and expect it to be the same the next time.

Does this help?  I'm not sure what I've answered or left unanswered.  If you have more questions, ask.
0
 

Author Comment

by:bod_1
ID: 1173639
Yes this helps a bit but something bad is happening.

A toolbar calls it's member combo box's Init() member function.  
The Init() member function gets the DC to itself.  It then changes font, colour, etc and fills the combo box with the required values.
The problem is that when I leave the DC to go out of scope and don't bother releasing it there are no problems ( changes made are reflected in the combo box, no mem leaks ), but when I call ReleasDC (the_pDC) at the end of my Init() routine (after filling combo box, just before return), the fonts, sizes, etc are all left to their defaults.

Whats going on?
1.  Maybe CComboBox::InsertString() function returns immediately (ie. hasn't finished the work when the DC is released).
2.  Maybe when the DC goes out of scope it is automatically released by MFC?
3.  maybe I should just keep the DC and say ta hell with it.

Attempted workarounds
1.  Tried to add a Sleep() statement after my function which uses CComboBox::InsertString() to make sure that it had finished it's work when the DC was released.

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Got It
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
My workaround that worked was to make the CMyComboBox::Init() function return a CDC*.  The CDC* was then released in the tool bar's calling function.
BOOL CMyToolBar::Init()
{
//...
CDC* pDC = m_MyComboBox.Init();
ReleaseDC(pDC);
//...
}

Guess that the lesson here is that if you're using a DC to change attributes of a device (window, combo box anyway), you must release the DC in a function that is completely separate from the DC function or else you'r changes wont be made (cant call ReleaseDC() in the same function in which you manipulated the DC).

-------------------------------------------------------------------------------------------------------------------------
THE QUESTION
-------------------------------------------------------------------------------------------------------------------------
In sample programs I've gotten from Microsoft and the web I always see things like this in functions:
void AClass::SomeFunc()
{
CClass* pClass = new CClass;
//..
}
Seems to be sort of a rule that if you allocate memory (new) you must release it (delete).
How do you delete a pointer to an object if the function that created that object goes out of scope right after you create it?
0
 
LVL 22

Expert Comment

by:nietod
ID: 1173640
1.  Maybe CComboBox::InsertString() function returns immediately (ie. hasn't finished the work when the DC is released.  

That should not be the problem.  This should be a "synchronious" call.  It does not return until it is finished.  Thankfully, very few things in the Windows API operate asynchronously.

2.   Maybe when the DC goes out of scope it is automatically released by MFC?

This is a possibility.  I don't know enough about MFC and I don't know enough about your code yet.

3.  Maybe I should just keep the DC and say ta hell with it.
   You can say "ta hell with it"  You probably won't be able to type it however.  Windows applications must work well with the OS and with each other.  There are millions of things an application can do to make a total mess out of the system.  Of all the resources you can consume needlessly global DC's are the worst.  There are 5 and when they are gone, they are gone.

0
 
LVL 22

Expert Comment

by:nietod
ID: 1173641
>>My workaround that worked was to make the CMyComboBox::Init() function return a >> CDC*.  The CDC* was then released in the tool bar's calling function.

That is a common algorithm.  for many things.  But the caller must remember to delete the object returned ot there will be memory leaks.  (there are advanced techniques (reference counting) that can automate this so you never need to delete an object again.  But I don't think you are ready for that yet.  Keep it in mind.  Makes programming simpler and safer.)

>> Guess that the lesson here is that if you're using a DC to change attributes
>> of a device (window, combo box anyway), you must release the DC in a function
>> that is completely separate from the DC function or else you'r changes wont
>> be made

No.  That's not right.  Why do you think that?  What was your code like before this change?

0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 22

Expert Comment

by:nietod
ID: 1173642
>> How do you delete a pointer to an object if the function that created that
>> object goes out of scope right after you create it?

It is impossible.  That would be a bug.  However, the function could return the pointer, in which case, it is up to the caller to delete the object.  Also make sure you are not looking a "condendsed" examples where sections of code have been removed to make the example smaller.  Some documentation assumes the reader can fill in the clean up code.

About your first code example, I didn't really detail the problems within it.  Do you understand it?  
0
 

Author Comment

by:bod_1
ID: 1173643
What was your code like before this change?
- I simply created a CDC* to the combo box object.  I used the DC* to change a few things and finally return the count of the items in the combo box.  
No clean up or release of the CDC*.  
I was expecting memory leaks but non occurred.

- My workaround changed the return value to CDC* so I could return the newly created CDC* to the calling function and have that function release it.

You said that that is a common algorithm which really helps me out.  When I'm working with new functions and objects and I'm having problems,  that'll be one of the things I'll look out for.
------------------------------------------------------------------------------------------------------------------
About your first code example, I didn't really detail the problems within it.  Do you understand it?

-  In my first code sample I was thinking of ways in which I could delete the CDC* on destruction of the class.  My idea was to use a void* as a member of my class and make that pointer equal the CDC*.  Then I was hoping to delete "what the void pointer was pointing to"(the DC) using the indirection operator (*) but the compiler didn't like that.
It was a stretch and I didn't really expect it to work.
//Header
void * mp_DC;

// A function
//... Gets a pointer to the DC for the window, pDC
mp_DC = pDC;

// Destructor tries to delete what the void* is pointing to (the pDC).
CMyClass::~CMyClass()
{
delete *(CDC( m_pDC) );
}
Was hoping that the compiler would see this as:
delete what the void* is pointing to, casting it to CDC type.
Compiler didn't see it that way.
Anyway it is good to know that my workaround is used in more than just one situation.
------------------------------------------------------------------------------------------------------------------
(there are advanced techniques (reference counting) that can automate this so you
       never need to delete an object again.

Are you talking about Semaphores here?
Right now I'm reading and going over code which implements synchronization classes.
Planning on implementing them in this program actually.
Another couple of days and I think I'll have the jist of them but you're right about it being an advanced technique, a crucial one none the less, and my next step.
------------------------------------------------------------------------------------------------------------------
THE QUESTION

What are some common teqniques to dynamically allocate or free memory (ie, a condition is met, must create an object, use it, free it when done).

I haven't really read much on memory management.  Guess I should add that to my list.
Am i right to do this?
- Create a pointer for the object in your class' header.
- If you need to use the pointer create the object using the new operator.
- On your classes destruction, if the pointer points to an object, delete it.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1173644
>>   No clean up or release of the CDC*. I was expecting memory leaks but
>>   non occurred.

      About your first code example, I didn't really detail the problems within it.  Do you understand it?

>> My idea was to use a void* as a member of my class and make that pointer
>> equal the CDC*.  Then I was hoping to delete "what the void pointer was
>> pointing to"(the DC) using the indirection operator (*) but the compiler didn't
>> like that.

But why?  Why would you want the void * at all?  just delete with the pointer to the CDC.

>>      delete *(CDC( m_pDC) );
>>      Was hoping that the compiler would see this as:
>>      delete what the void* is pointing to, casting it to CDC type.

You could do

void * m_pDC = new CDC;
delete (CDC *) m_pDC;

But there is no reason to.  just do.

CDC *m_pDC = new CDC;
delete m_pDC;

That's easier and safer.

>>      Are you talking about Semaphores here?

No.  Allocating things and not deleting them is the root of most bugs in windows.  It can cause horrible problems that can be impossible to track down.  There are techniques for creating class that manage other classes so that the things are automatically released when no longer needed.  In essences, you create a local variable that of some class that manages a DC class for you.  As long as the local variable or some copy of it exists, the DC class will exist.  If the local variable goes out of scope the CDC class will be destroyed.  The nice things is that this local variable can be passed to other functions or returned from the function that creates it.  If it is returned from the function, then the caller can use it to access the DC.  However, unlike in your design, the caller does not have to remember to delete the DC.  If they use the return value the DC will continue to exist until they are done with it.  If they ignore the return value the DC will be automatically deleted right after the return.  This prevents the type of errors that your code is open to where the caller might not delete the return value.

>>  What are some common teqniques to dynamically allocate or free memory
>>  (ie, a condition is met, must create an object, use it, free it when done).

I'm not sure what you are asking?  

>>  - Create a pointer for the object in your class' header.
>>  - If you need to use the pointer create the object using the new operator.
>>  - On your classes destruction, if the pointer points to an object, delete it.

That design is often used.  But there are lots of dangers.  

If you don't always create an object for the class, the pointer must be set to NULL.  Otherwise it will contain a garbage value and the delete will cause a crash.

You must write a copy constructor and an assignment operator for the class.  If you do not, and if either function is used (which is likely unless you are REALLY careful) you will end up with two objects that both have pointers to the same object.  Whe the first object is destroyed the pointer is deleted and things are fine.  When the second object tries to use the pointer you get a crash.  If the second object doesn't try to use the pointer, but is instead destroyed, it will try to delete with the pointer and it will crash.  Either way you get a crash.

I strongly recomend you get the Effective C++ and More Effective C++ books by Scott Meyers.  These are considered by many to be the best C++ books on these sort of non-introductory/avanced techniques.  You might not be quite ready for them.  But you will be soon.  They deal with these type of problems and their solutions.
0
 

Author Comment

by:bod_1
ID: 1173645
Hey Nietod,
Sorry about not getting back  sooner, up at the cottage (damn balackflies had a feast!!).

I did a bit of reading on memory management and jeez, was I ever missing out on a lot of concepts!  I've really got to read more before I go and ask stupid questions.
After reading up a bit on the topic I wonder how most of my programs ever worked!  They shouldn't have.  
eg.  A few of them were about 100k, never used any kind of memory allocation (at least knowingly), but they still ran.  From what I've read (still another few chapters to go), each process in windows is alloted only 1 segment of memory!  I guess I got lucky that some of my programs ran at all! (maybe because they were debug builds)

I'm posting a new question on a few confusing details like why a program can run in debug mode but the same program in release build wont get past it's 4th op-code.
My guess is that it exceeds the 64k segment (would be nice if you could find out how much of your local heap you've used up).

Anyway, thanks for the help.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1173646
A 16 bit program has a maximum heap size of 64K  (almost always less than that).  A 32 bit program has a heap size of many meg.  1 meg is probably a reasonable MINIMUM..  We are talking different beasts here.
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now