C++ - is this a valid way of checking a pointer in windows?

Started by
6 comments, last by JesseT 19 years, 7 months ago
say i have a function that accepts a pointer. i'd like to see if this pointer is a valid pointer (i.e. will not cause an access violation if i try to use it). why do i want to check it? because "memory access violation" is not helpful, and i don't feel like tracking them down every time with the stepthru debugger. it would be nice to be able to pop up my own message box with a message like "so-and-so pointer is invalid in function fork()" or whatever. it would make debugging much easier. anyway i found that a memory access violation will throw an exception. so i tried this and it works (assume ErrorBox() just pops up an error and quits):

void fork(int* p)
{
    try
    {
        *p=*p;
    }
    catch(...)  // edit: forgot the (...)
    {
        ErrorBox("Pointer P is invalid in function fork()");
    }

    // do stuff with p
}
it works, but what i'd like to know is if this is a safe/reliable way of checking, and if there are any caveats about this method. :)
_______________________________________________________________________Hoo-rah.
Advertisement
Quote:Original post by Drakex
if there are any caveats about this method. :)


erm... don't use it? it's slow and won't work in all situations. your pointer could still point to valid memory space so your test would pass. also, it's just lazy. it's not that hard to track down bugs like bad pointers. they're some of the easier bugs to fix simply because they crash so hard rather than just adding wierd perceptual things to your game. if you find yourself getting memory exceptions all the time then your use of pointers is probably bad. do you reset pointers to NULL after calling delete on them? do you use weak pointers like the boost smart_pointer so that other objects referencing an object through a pointer will automatically get set to NULL when you delete the object? the only pointer verifying you should need to do is:

if ( pointer != NULL ){    doStuff;}


you should definitely make friends with your debugger. at least 50% of coding is spent debugging your work and debugging is faster inside a debugger. :)

-me
A way I use personally and see often is just to make sure any pointers you are not using are initialized to NULL.

If you destroy a pointer then set it back to NULL(0) after it's been destroyed.

That way when you want to test a pointer in a function you simply do a basic logic check:

if(!pointer)
// Pointer is invalid(set to NULL).


Again, this is just my personal way I do things.
What you're doing, basically, is a less efficient version of calling IsBadReadPtr() and IsBadWritePtr() (which see MSDN). Except that it won't always catch bad pointers, if the allocator being used has allocated extra memory from the OS and the pointer happens to point to this extra memory. And depending on your compiler it might not work at all, because the results of reading/writing unallocated memory are undefined. And, of course, the assignment may have side effects, especially given that people often forget to write assignment operators in a self-assignment-safe manner.

Bottom line: NOOOOOOO!!!! (runs away screaming)
Quote:Original post by Drakex
but what i'd like to know is if this is a safe/reliable way of checking, and if there are any caveats about this method. :)


No it looks very unreliable, for one you doing self-assignement if do that with user defined types and some body forgot to check for this then bang.

My advice is to write less code with pointers.

1. for one you can start using reference types for function arguements don't use pointers for the sole purpose to do pass-by-reference which is simulated pass-by-reference with pointers because pointers are variables to its still really pass-by-value because its a copy of address and not the instance it refers to.

2. If you need to share an instance temporary, again you can use reference types for this or try using smart pointers.

3. you can use standard library containers to replace using pointers to raw arrays allocated on the heap, they take care of memory management for you.

4. You need polymorphic behaviour or to store heterogeneous elements in STL containers then use smart pointers instead they know how & when to delete, boost has some good smart pointers you can use.
One way is to step through the heap and check the pointer against allocated blocks. When you allocate a block of memory, the C/C++ run time puts housekeeping information either end of the allocated memory - links to next / previous blocks, size, type, guard bytes and so on. If you've got the source to the run time libraries then you can find the structure used by the memory allocator and process the heap accordingly.
If you haven't got access to the source then either work out the format of the housekeeping data or keep a track of all the allocated memory blocks in a list somewhere and use that instead.

Skizz
this isn't so much for me as it is for people who will be using what i write. i have no control over what the people who use something i write will do with pointers (i can't assume they will always set the pointer to NULL, etc.). additionally, this isn't something that i'd always use - it would only be in the debug build and would be removed in the release build.

i don't know about you, but trying to debug a 3000-line program line by line is not fun. especially when the error tells me nothing about where it occurred.

i'm hating C++ more and more every day. i can't wait until D is useable ;)

but until it is, i guess i'll use IsBadRead/WritePtr(). thanks sneftel.

skizz - i know what you're talking about but that seems like a rather inefficient method of doing it :P

thanks all.
_______________________________________________________________________Hoo-rah.
Drakex,

Firstly, and I in no way mean to insult you, but the whole concept of checking to see if a pointer is valid seems to imply that the rest of your code is not robust. There are idioms and methodologies that you can use during implementation to increase the robustness of your code. Many of these have already been listed by snk_kid, ChaosPhoenix, and paladine.

Remember, you're programming in C++, and thus you are not limited to the confines of C, even if your programming style is more procedural than object-oriented.

1. Use references when passing arguments by reference to functions.
2. Utilize the const modifier to specify the immutability of such reference arguments that you do not want changed inside of a function body.
3. Use standard C++ library (STL) containers over dynamically allocated arrays.
4. Utilize the 'Resource Acquistion Is Initialization' idiom to automate cleanup and enforce exception safety of resources such as memory. Smart pointers are an excellent example of this idiom in action.
5. Prefer to use '0' over 'NULL'. In standard C++, a null pointer is always equal to a cardinal value of zero. If the compiler has it specified as otherwise, than it is not standards compliant. In the next revision of C++, ISO C++ 0x, the keyword 'nullptr' will be introduced which acts as referencable constant. 'null_ptr' already exists as a part of the upcoming ISO/ECMA C++/CLI standard (post-whidbey managed C++). So perhaps create a global 'nullptr' object with overloaded equality operators parameterized for all pointer types to use until it becomes included in most compilers.
6. Use classes and proper single-stage construction to encapsulate and enforce invariance rules. Always initialize member variables and allocate resources in a constructor, or ensure that resources are guaranteed to be allocated on demand when any member function of the class is called. Don't have a secondary 'Initialize' member function, as this forces the programmer into a dangerous game of two-step initialization. Once the constructor maintains a given invariance rule (ie. the range of member variable 'scrollPosition_' is between 0 and 100), then make sure all other member functions leave an object of the class in a valid state as well. Writing code in this manner allows you to remove a lot of if-then error checking.

In my experience, I rarely have to check for null or invalid pointers, and the code becomes much cleaner and more robust.

This topic is closed to new replies.

Advertisement