[ros-dev] Re: 18113:-reorderInsertXscendingOrder macro argument order and update uses

Joseph Galbraith galb at vandyke.com
Wed Sep 28 18:22:30 CEST 2005


Nathan Woods wrote:
> Richard Campbell writes:
>> Hate to throw my 2 cents in, but why use macros or goto statements at 
>> all?  None of the demonstrated code actually needs a goto statement to 
>> work.  Granted i've not seen the actual offensive code , but all 
>> examples here can be written without goto statements or macros.  Why 
>> bother using either?  At any rate, i'm inclined to agree that macros 
>> are a bad idea.  Hiding a mess behind a preprocessor is considered bad 
>> coding practice.
> 
> While the previous examples can ge accomplished cleanly without gotos 
> and/or macros, the rules can be different when the code is far more 
> complicated.  For instance, the handling of error conditions buried deep 
> within multiple for loops and other statements.  Take the following 
> example:
> 
> BOOL NtFunc()
> {
>   BOOL bSuccess = FALSE;
>   LPVOID *pPointer = NULL;
>   LPVOID *pAnotherPointer = NULL;
> 
>   for (...)
>   {
>       if (ThisOperationCanFail())
>           goto cleanup;
> 
>       pPointer = malloc(...);
>       if (!pPointer)
>            goto cleanup;
> 
>       while (...)
>       {
>           if (ThisOperationCanFailAlso())
>              goto cleanup;
>           ....
>           if (!pAnotherPointer)
>           {
>              pAnotherPointer = malloc(...);
>              if (!pPointer)
>                 goto cleanup;
>              if (YetAnotherCanFail())
>                  goto cleanup;
>              ...
>           }
>       }
>       free(pPointer);
>       pPointer = NULL;
>   }
>   bSuccess = TRUE;
> cleanup:
>   if (pPointer)
>       free(pPointer);
>   if (pAnotherPointer)
>       free(pAnotherPointer);
>   return bSuccess;
> }
> 
> 
> pPointer and pAnotherPointer are both pointers with different lifetimes; 
> making things a bit messy.  While it is possible to write such code 
> without gotos or macros, it would involve checking and freeing those 
> pointers from many different places.  Using a cleanup label provides a 
> convenient place to centrally locate all cleanup code.

Of course the real solution to this problem is the following
simple C++ class (which I'm not really arguing we should use...
I'm just throwing some gasoline on the flames :-)

template<class T>
class NPagedPointer
{
public:
     inline NPagedPointer(T* p) : m_ptr(p) {}
     inline ~NPagedPointer()
     {
        if ( m_ptr )
            ::ExFreePool(m_ptr);
     }

     inline operator T*() { return m_ptr; }
};

BOOL NtFunc()
{
   NPagedPointer<PLUGH> pAnotherPointer;

   for (...)
   {
     if (ThisOperationCanFail())
       return FALSE;

     NPagedPointer<XYZZY> pPointer = malloc(...);
     if ( ! pPointer )
       return FALSE;

     while (...)
     {
       if (ThisOperationCanFailAlso())
         return FALSE;

       ....

       if ( ! pAnotherPointer)
       {
         pAnotherPointer = malloc(...);
         if ( pAnotherPointer )
           return FALSE;
         if (YetAnotherCanFail())
           return FALSE;
         ...
       }
     }
   }

   return TRUE;
}

See, no cleanup code needed :-)

Of course, people don't like to use C++ in the kernel, and not
everyone has agreed to learn C++ (anymore than they've agreed to
learn Zimbobwean.)  And it can be tricky to make sure the C++
compiler doesn't mess you up (like putting the generated template
code in a paged section if you have one.)

Thanks,

Joseph


More information about the Ros-dev mailing list