matthew.chaboud.com

January 18, 2007

Forgive me coders, for I have…

Filed under: — admin @ 12:56 am

C++ is a language that regularly presents things that make me laugh and cringe at the same time. It, more than any modern language I use that starts with “C” and ends with a non alphanumeric character, provides me enough rope to create things that seem useful on the surface but are really ugly when you think about the possible uses. This may not be as bad as the lazybuffer (think std::vector, except any [] access beyond the end of the array leads to the extension of the container to make the ref to that address valid, and also add an optional default value), but it could definitely lead to some ugly, and invisible, code.
This came about towards the end of Bob showing me his trick for writing an operator new that explicitly throws, akin to a new(nothrow), but the other way around.
In our codebase (or, really, any codebase), that trick is likely more useful than the following.
Imagine this code:

int _tmain(int argc, _TCHAR* argv[])
{
   int Out = 0;
   HRESULT hr = S_OK;
   printf("Start running - Int is %d, HRESULT is 0x%.8X\n", Out, hr);
   Out = DoSomethingInt(S_OK, 1);
   printf("return to Int - Int is %d, HRESULT is 0x%.8X\n", Out, hr);
   hr = DoSomethingInt(E_FAIL, 2);
   printf("return to HRESULT - Int is %d, HRESULT is 0x%.8X\n", Out, hr);
   RWrap(hr, Out) = DoSomethingInt(E_INVALIDARG, 3);
   printf("return to Both - Int is %d, HRESULT is 0x%.8X\n", Out, hr);
   _getch();
   return 0;
}

and imagine that the output could be:

Start running - Int is 0, HRESULT is 0x00000000
return to Int - Int is 1, HRESULT is 0x00000000
return to HRESULT - Int is 1, HRESULT is 0x80004005
return to Both - Int is 3, HRESULT is 0x80070057

It can be, without any severe trickery. The point is to be able to handle optional error return values without losing the simplicity of regular return values and, of course, to do so without exceptions. Here’s everything. Just make a console app in the wizard and drop this code in:

// MultiReturn.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>;
#include <conio.h>
template <typename FirstType, typename SecondType>
class MultiReturn
{
   protected:
     FirstType First;
     SecondType Second;
   public:
     MultiReturn(FirstType FirstInit, SecondType SecondInit)
     {
       First = FirstInit;
       Second = SecondInit;
     }
     void Set(FirstType FirstIn, SecondType SecondIn)
     {
       First = FirstIn;
       Second = SecondIn;
     }
     operator SecondType() const
     {
       return Second;
     }
     operator FirstType() const
     {
       return First;
     }
};
template <typename FirstSet, typename SecondSet>
MultiReturn<FirstSet, SecondSet> tReturn(FirstSet FirstIn, SecondSet SecondIn)
{
   return MultiReturn<FirstSet, SecondSet>(FirstIn, SecondIn);
}
template <typename FirstType, typename SecondType>
class MultiRef
{
   protected:
     FirstType *pFirst;
     SecondType *pSecond;
   public:
     MultiRef(FirstType &FirstIn, SecondType &SecondIn)
     {
       pFirst = &FirstIn;
       pSecond = &SecondIn;
     }
     MultiRef& operator=(const MultiReturn<FirstType, SecondType> &rIn)
     {
       *pFirst = (FirstType) rIn;
       *pSecond = (SecondType) rIn;
       return *this;
     }
};
template <typename ErrorType, typename ContainedType>
MultiRef<ErrorType, ContainedType> RWrap(ErrorType &error, ContainedType &contained)
{
   return MultiRef<ErrorType, ContainedType>(error, contained);
}
MultiReturn<HRESULT, int> DoSomethingInt(HRESULT hrIn, int input)
{
   return tReturn(hrIn, input);
}
int _tmain(int argc, _TCHAR* argv[])
{
   int Out = 0;
   HRESULT hr = S_OK;
   printf("Start running - Int is %d, HRESULT is 0x%.8X\n", Out, hr);
   Out = DoSomethingInt(S_OK, 1);
   printf("return to Int - Int is %d, HRESULT is 0x%.8X\n", Out, hr);
   hr = DoSomethingInt(E_FAIL, 2);
   printf("return to HRESULT - Int is %d, HRESULT is 0x%.8X\n", Out, hr);
   RWrap(hr, Out) = DoSomethingInt(E_INVALIDARG, 3);
   printf("return to Both - Int is %d, HRESULT is 0x%.8X\n", Out, hr);
   _getch();
   return 0;
}

Powered by WordPress