 |
|
 |
I found this an interesting article and agree with the sentiment that a program should either believe it is working correctly or bale out. With regard to memory leaks, I would like to add my own modest contribution.
The debugging version of the C/C++ runtime library can tell you if you have a memory leak. Well, up to a point, anyway. Just before your program terminates, and (importantly!) after all your destructors have been called, make a call to _CrtDumpMemoryLeaks (), and if it returns a non-zero value take some action (such as breaking into the debugger, in debug builds).
This works best if you are rigorous about deleting every object you ever create, which not all programs are, and, unfortunately, if you use static objects (which I never do, personally), their destructors are only called after WinMain returns, which obscures the picture a little. However, this function also dumps a list of all allocated data blocks to the debugger's output window, which might be helpful even if some of them are legitimate.
Which leads me on to my second point The other thing to do is, in debug builds, to write your own version of new (), like this:
#ifdef _DEBUG
void * operator new (size_t nbytes, const char *file, int line)
{
return _malloc_dbg (nbytes, _NORMAL_BLOCK, file, line);
}
#define my_new new (__FILE__, __LINE__)
#else
#define my_new new
#endif
And then use my_new throughout your code instead of new.
This is a bit of work to set up, but it means that you get file and line number information listed in the trace produced by _CrtDumpMemoryLeaks (), which makes all the difference. I have found numerous problems in my own code this way and now have a zero-tolerance policy on memory leaks.
Also, to avoid leaking GDI handles (which is worse, actually, is it can bring the whole system to its knees), checkout http://msdn.microsoft.com/msdnmag/issues/03/01/GDILeaks/[^]
-- modified at 12:32 Saturday 20th October, 2007
|
|
|
|
 |
|
 |
hi great article. But its of no help to check against NULL before deleting an object. Rather its worthless.
for eg.
int *myInt = new int;
if( myInt ){
//do something.
}
//we are done, so deleting
delete( myInt );
myInt = NULL; //better to set the pointer to NULL after deletion.
//there is no harm in executing the following statement now.
//The point is that we are no longer pointer to the memory.
delete( myInt );
satindar kumar
|
|
|
|
 |
|
 |
int main()
{
try{
int *p=NULL;
*p=10;
if(p==NULL)
throw std::bad_alloc();
}
catch(...)
{
std::cout<<"Exception is caught";
}
return 0;
}
|
|
|
|
 |
|
 |
By work, do you mean that it prints out "Exception is caught"?
As you said on Linux the segmentation fault is not caught by the catch - I tried myself. Perhaps in Windows it IS caught. I can't reboot to find out right now. I would be surprised if the Windows version made it to the if statement.
Nigel Atkinson
"Land a'hoy!" * CRASH * "I should av said that sooner eh?" - Eckles, The Goon Show
|
|
|
|
 |
|
 |
Hi Dwijendra,
Why is it so?
The memory for the integer pointer hasn't been allocated ( you would use 'new' to allocate the memory ), nor has any attempt to allocate memory failed. The program therefore attempts to write to an invalid memory address. How an operating system responds to this situation is evidently operating system dependant. There is no reason to assume the operating system will throw an exception. A segmentation fault is a reasonable response. Hopefully you get some sort of error/exception with VC7.1/Windows also.
|
|
|
|
 |
|
 |
Be very careful with signal handlers. Technically, in the ANSI C standard, the only function that is guaranteed safe to call in the handler is signal. In practice, of course, this is not very useful; usually one wants to do more; and usually many functions can be safely called.
However, some things must be avoided. I know from practical experience that, on Unix, performing UI operations (Xlib calls, if you're familiar with the platform) - even simple ones - is not safe; it can actualy cause your program to loop in some cases!
In general, the more complex the function you're calling - or, more specifically, the more "state" information it has - the more likely you are to run into problems.
In a product I worked on, the signal handler uses low-level system calls to print messages, and executes another program to display an error message. Unfortunately, some cleanup is required, but that is minimized as much as possible. This is done so that the signal handler is known to be as safe as possible.
|
|
|
|
 |
|
 |
In the C++ standard, new does not return NULL (or 0, actually) if the allocation fails. From Section 6.2.6.2 Memory Exhaustion of The C++ Programming Language:
What happens when new can find to store to allocate? By default, the allocator throws a bad_alloc exception. For example:
void f()
{
try {
for ( ; ; ) new char[10000];
}
catch (bad_alloc) {
cerr << "Memory exhausted!\n";
}
}
Thus, it is not necessary to check for 0 (NULL) after calls to new.
Any compiler that doesn't do this does not follow the ANSI C++ standard.
Of course, if someone overrides new and does return 0 on failure, you'll need to check. This is bad style, though.
Similarly, you don't need to check for a null pointer when calling delete. From section 6.2.6 Free Store:
Applying delete to zero has no effect.
(Technically, C++ does not have a NULL; instead, the constant 0 is used instead.)
Thus, your code:
if (ptr != NULL) {
delete ptr;
}
can more easily (and just as safely) be coded as:
delete ptr;
ptr = 0;
As an aside, the C memory routines - malloc/free - may not accept allocations of zero size, or freeing NULL; in this case it is good practice to avoid freeing NULL, although most modern compilers will allow both.
|
|
|
|
 |
|
 |
pls see this comment
http://www.codeproject.com/useritems/Guidelines.asp?df=100&forumid=16724&fr=26&select=601628#xx601628xx
"A robust program is resistant to errors -- it either works correctly, or it does not work at all; whereas a fault tolerant program must actually recover from errors."
|
|
|
|
 |
|
 |
It takes some getting used to, but I've found that redefining new() to throw an exception instead of returning NULL can lead to more maintainable (if not more readable) code. This way, you can avoid having so many if...else constructs when grouping operations in a single try..catch is more appropriate. IMO, failure to allocate memory is almost always more of an exception-style case that may not always need explicit checking throughout the entire program.
void* operator new(size_t size)
{
void* pMem = malloc(size);
if(pMem == NULL) throw(CException("Failure to allocate memory."));
return(pMem);
}
Of course, this may not be at all desireable if you're using new() as an initalizer for static data. In that case, rather than expecting a pointer's value to at least be NULL, it would be unitalized. (provided, of course that the CRT_init for the application somehow handles the exception gracefully)
- Eric
Calling a function is like tying your shoe. Remoting a function is like tying someone else's shoe... while they're running around... in China.
|
|
|
|
 |
|
|
 |
|
 |
Thanks for all your suggestions.
Go on giving such constructive criticisms....!!!
"A robust program is resistant to errors -- it either works correctly, or it does not work at all; whereas a fault tolerant program must actually recover from errors."
|
|
|
|
 |
|
 |
Most of this article are verbatim copies from serveral other articles available on different sites on the internet. While it might serve as a compendium I think it's really bad manors to "forget" to name those sources...
A couple of examples...
Bits of "Using Exceptions"
here
"A little bit of Unix flavour"
here and
here
"Using DEBUG functions"
here
|
|
|
|
 |
|
 |
Most of points I have qouted here are also available in other sites. But While compiling this article, I only had the intension of getting these 'thumb rules' to others from single point.
I will be updating this article soon, and this time I am not going to forget the name to those sources...
"A robust program is resistant to errors -- it either works correctly, or it does not work at all; whereas a fault tolerant program must actually recover from errors."
|
|
|
|
 |
|
 |
The exception part of your description is a shameless rip of Jack W. Reeves article from 1996. It is "not available on other sites", but you have STOLEN his EXACT WORDING without giving the credits!!!
The original article is here, anyone who wants should be able to see the EXACT WORDING, which is especially shameful when this article here has taken Jack's word about his EXPERIENCES while working with exceptions:
"When I started to use exceptions, it rapidly became apparent that exceptions are much more difficult to use effectively than it first appears. In fact, the more I explored how exceptions can interact with non-exception handling code, the more convinced I became that exceptions may be the most difficult feature of C++ to use."
http://www.bleading-edge.com/Publications/C++Report/v9603/Article2a.htm
Shame on you for stealing that article, and shame on you for publishing an old (out-of-date) article without telling that many of its advices are NOT CONSIDERED good today.
Shame on you!
|
|
|
|
 |
|
 |
The article is really just a couple rules of thumb. The article title seems to indicate more. One part of developing applications that always decease gracefully is testing. Also it seems that you assume some things about a developer and not others. Why would someone know that he/she should always catch exceptions by reference, but not already know that they need to avoid memory leaks? It really looks like you got tired of typing than really thinking about whether the level of the reader would know why he/she should catch exceptions by reference.
Anyway, the intention of the article is good, and I commend that! Don't give up! I definately do not want to discourage you from writing more articles. Please take this as constructive criticism!!!
Regards,
Kevin
|
|
|
|
 |
|
 |
I partly agree with what you say. It might be better though to provide a link to an explanation otherwise the article would be too long.
|
|
|
|
 |
|
 |
I have found it helpful (especially since my code is peppered with ASSERTs) to NULL out a heap-created pointer after deleting it. if (NULL != m_pPtr) {
delete m_pPtr;
m_pPtr = NULL;
}/ravi
Let's put "civil" back in "civilization"
Home | Articles | Freeware | Music
ravib@ravib.com
|
|
|
|
 |
|
 |
Good suggestion. Ignoring smart pointers, etc, it might be better to use a SafeDelete template function (or macro) to save time.
Now follows a nit-pick warning. Danger!
Ravi Bhavnani wrote:
if (NULL != m_pPtr)
In english that is "if null is not equal to m_pPtr". You should put the NULL on the other side :p
|
|
|
|
 |
|
 |
dog_spawn wrote:
In english that is "if null is not equal to m_pPtr".
Quite right.
But you tend to enforce this coding standard (literal values on the left of a boolean expression) after the first few times you encounter bugs like this: if (foo = NULL)
...;/ravi
Let's put "civil" back in "civilization"
Home | Articles | Freeware | Music
ravib@ravib.com
|
|
|
|
 |
|
 |
You do indeed encounter bugs like that. You can avoid it by declaring an extension in the form of a macro:
#define equals ==
Well, that is a bit silly In Visual Studio I notice C# gives you a warning (or is it error?) if you make this mistake. Perhaps the MSVC should do the same thing. Maybe it does, I can't remember...
|
|
|
|
 |
|
|
 |
|
 |
Ravi Bhavnani wrote:
Lint will catch it.
Lint catches damn close to everything.
I'm having fun running it on our product at the moment...especially as I seem to the only one in the team who guards pointers as a matter of course...
FYI there's a potential article in the pipeline (company agreement permitting) on that subject - a simple command line utility that runs PC-Lint on an entire VC6/7 project or workspace, and produces HTML output...
Anna
Homepage | Tears and Laughter
"Be yourself - not what others think you should be"
- Marcia Graesch
"Anna's just a sexy-looking lesbian tart"
- A friend, trying to wind me up. It didn't work.
Trouble with resource IDs? Try the Resource ID Organiser Visual C++ Add-In
|
|
|
|
 |
|
 |
dog_spawn wrote:
Perhaps the MSVC should do the same thing
It does. "Warning C4706 - assignment within conditional expression". It is a level 4 warning (VC6.0 anyway)
Sonork 100.11743 Chicken Little
"You're obviously a superstar." - Christian Graus about me - 12 Feb '03
Within you lies the power for good - Use it!
|
|
|
|
 |
|
 |
Hooray for MSVC! I knew there was a reason why I used it.
|
|
|
|
 |
|
 |
Yes it does, but NOT ALLWAYS.Big projects usually have this problem.I had a project in which in one source the "if(a=NULL)" was detected and in another it was not detected. After all, MS from "MSVC" means "Microsoft".
Does anyone know how to replace the operator delete SAFELY so it will also
null the pointer on which it is applied?
|
|
|
|
 |