 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
OBQuiet Guest
|
Posted: Sat Jun 11, 2005 10:30 am Post subject: Question: Separating conversion on return from conversion by |
|
|
IS there a way to detect and handle the separate cases of type
conversion?
Specifically, I am trying to come up with a class to substitute for an
error code, the Microsoft HRESULT which is a typdef for long, that can
warn if it is not checked.
It would be pretty easy to provide operators like =, ==, <= or ! that
flag it as tested or untested.
Unfortunately, the most common way to use it would be through a macro,
SUCCEEDED(hr), that casts the object to an HRESULT before comparing. I
thought about having the conversion itself mark the object as checked
but that also eliminates the check when the item is returned as an
error code.
So I am looking for a way that code behave as described below but I
think I am out of luck. I have the feeling I am missing something
though so I thought I might ask here.
HRESULT myMethod(){
SmarterHR hr;
hr = E_FAIL;
return hr; // executing this line or hr's destructor
// will do something to flag the error
}
void MyOtherMethod(){
SmarterHR hr;
hr = myMethod();
if(SUCCEEDED(hr))// #define SUCCEEDED(Status) ((HRESULT)(Status) >=
0)
std::cout<<"It worked!"<
}// here the code run fine
void YetOtherMethod(){
SmarterHR hr;
hr = myMethod();
} // Once more this should flag an error
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Greg Guest
|
Posted: Sun Jun 12, 2005 3:32 pm Post subject: Re: Question: Separating conversion on return from conversio |
|
|
OBQuiet wrote:
| Quote: | IS there a way to detect and handle the separate cases of type
conversion?
Specifically, I am trying to come up with a class to substitute for an
error code, the Microsoft HRESULT which is a typdef for long, that can
warn if it is not checked.
It would be pretty easy to provide operators like =, ==, <= or ! that
flag it as tested or untested.
Unfortunately, the most common way to use it would be through a macro,
SUCCEEDED(hr), that casts the object to an HRESULT before comparing. I
thought about having the conversion itself mark the object as checked
but that also eliminates the check when the item is returned as an
error code.
So I am looking for a way that code behave as described below but I
think I am out of luck. I have the feeling I am missing something
though so I thought I might ask here.
HRESULT myMethod(){
SmarterHR hr;
hr = E_FAIL;
return hr; // executing this line or hr's destructor
// will do something to flag the error
}
void MyOtherMethod(){
SmarterHR hr;
hr = myMethod();
if(SUCCEEDED(hr))// #define SUCCEEDED(Status) ((HRESULT)(Status) >=
0)
std::cout<<"It worked!"<
}// here the code run fine
void YetOtherMethod(){
SmarterHR hr;
hr = myMethod();
} // Once more this should flag an error
|
The role of the SmarterHR class is not to check result codes for
errors itself, but rather to ensure that result codes are checked
for errors (by other code). Therefore it follows that the
requirements for the SmarterHR class are as follows:
A SmarterHR object must:
- Store the result code returned by a function call
- Make that result accessible via a HRESULT conversion operator
- Report an error whenever its HRESULT conversion function goes
uncalled between the time that a result is stored and up to
the time that either one of these two events occurs:
* the SmarterHR object is deallocated
* the SmarterHR object is assigned another result code
Note that it is the caller's responsiblity to check for an error
returned from the called function. It is not the called function's
responsibility to signal an error that it created itself. Specifically,
the comments in myMethod above do not describe the desired behavior.
This function should not signal an error since there is no certainty
that its error will go unchecked; clearly the caller can (and should)
check the HRESULT it returns. In other words, nothing should be
signaled in myMethod because its result has not (necessarily) gone
undetected.
One way to meet the requirements is for SmarterHR to maintain a bool
data member, mChecked, to track whether the stored result code has ever
been accessed via a conversion to an HRESULT (which happens both when a
SmarterHR object is used to return an HRESULT from a function call or
when it is used as an argument to the SUCCEEDED macro).
Whenever such a conversion occurs, SmarterHR sets its "mChecked" data
member to true; whenever a SmarterHR object is assigned (or constructed
from) an HRESULT, it sets its mChecked member variable to false. An
assert checks against the unchecked result error condition at
assignment and destruction.
Note that whether the HRESULT actually indicates an error or not is
irrelevant to the implementation - SmarterHR ensures the HRESULT is
always checked. After all, the worst possible time to find out that a
particular program is not checking for errors, is when there are errors
occurring for which it is not checking.
The SmarterHR implementation follows:
class SmarterHR
{
public:
SmarterHR()
: mHResult(0), mChecked( true)
{
}
SmarterHR(HRESULT inHResult)
: mHResult(inHResult), mChecked( false)
{
}
~SmarterHR()
{
assert(mChecked);
}
void operator=( HRESULT inHResult)
{
assert(mChecked);
mHResult = inHResult;
mChecked = false;
}
operator HRESULT()
{
mChecked = true;
return mHResult;
}
private:
HRESULT mHResult;
bool mChecked;
};
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
OBQuiet Guest
|
Posted: Sun Jun 12, 2005 9:52 pm Post subject: Re: Question: Separating conversion on return from conversio |
|
|
Greg,
Thanks fro taking the time to think about this.
You have the requirements correct and that was exactly how I originally
implemented it.
But I posted the question because I feel this solution failed in the
case of myMethod. The fact that this wasn't clear is my fault since I
was trying for brevity. Imagine instead that the function read
HRESULT myMethod(){
SmarterHR hr;
hr = SomeOtherMetrhod();
return hr; // executing this line or hr's destructor
// will do something to flag the error since hr is
unchecked
}
The fact that the error code is going to be forwarded up the call chain
cause the conversion operator to be called and the assert to be
skipped. This was the reason for my question about how I might seperate
the explicit cast from the implicit conversion.
While it might be a good idea to do so, I am not sure I can force the
use of seperate variables to hold error codes returned and error codes
to be returned.
Had SUCCEEDED not been implemented as a macro, it would be easy to
provide implementations of the comparision operators. More evidence of
the EVIL of using macros.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Greg Guest
|
Posted: Mon Jun 13, 2005 7:55 am Post subject: Re: Question: Separating conversion on return from conversio |
|
|
OBQuiet wrote:
| Quote: | Greg,
Thanks fro taking the time to think about this.
You have the requirements correct and that was exactly how I originally
implemented it.
But I posted the question because I feel this solution failed in the
case of myMethod. The fact that this wasn't clear is my fault since I
was trying for brevity. Imagine instead that the function read
HRESULT myMethod(){
SmarterHR hr;
hr = SomeOtherMetrhod();
return hr; // executing this line or hr's destructor
// will do something to flag the error since hr is
unchecked
}
The fact that the error code is going to be forwarded up the call chain
cause the conversion operator to be called and the assert to be
skipped. This was the reason for my question about how I might seperate
the explicit cast from the implicit conversion.
While it might be a good idea to do so, I am not sure I can force the
use of seperate variables to hold error codes returned and error codes
to be returned.
Had SUCCEEDED not been implemented as a macro, it would be easy to
provide implementations of the comparision operators. More evidence of
the EVIL of using macros.
|
The answer to the question about implicit vs explicit conversions is
"no", C++ has no explicit conversion functions, only explicit
constructors (though there is a proposal to add them to C++). To take
advantage of the explicit constructor would require redeclaring HRESULT
as an application-provided class.
An explicit conversion operator though is not a requirement in this
case, I believe, because myMethod() should not assert in the example
provided. The assert should be triggered only when a function result
goes unchecked. But does SomeOtherMethod's result go unchecked?
Remember that myMethod has an obligation to be sure that the result is
checked, but that does not mean that myMethod itself must perform the
check. Just as long as myMethod ensures that some code somewhere will
check it, myMethod is off the hook. And how can myMethod pull off such
a stunt? It can do so by noting that its caller (the one that called
myMethod) has the same obligation to check the result that myMethod
returns, as myMethod has towards SomeOtherMethod's result. Therefore by
making myMethod's result and the result returned by SomeOtherMethod,
one and the same, myMethod will fulfill its obligation without having
performed the check itself. myMethod effectively "passes the buck" in
this case to its caller.
Now in real life, offloading one's own duties for others to perform is
usually frowned upon. When programming C++, however, it is often
necessary to leave one's morals at home [just kidding]. But the
question is nonetheless valid: would the code be better, if myMethod
were obligated to check the results of called functions itself?
The answer is no. It makes no sense for any function to check for an
error, unless it cannot properly handle any error that such a check
would reveal. But often routines are called as one step in a larger
operation, and errors occurring at a lower level, are best interpreted
in the larger context and handled at a much higher level. If myMethod
is ill-equipped to handle errors, it does the right thing by forwarding
the error to its caller. Note that if myMethod called another function,
then it would have to deal with at least one of the results, because it
could not forward both results to its caller.
In C++ exceptions are usually used to make sure that errors are handled
at the appropriate level. But if exceptions are not an option in this
implementation, then the next best thing is to have errors percolate up
through a calling chain, until they hare handled at the right level.
In terms of a practical implementation, it probably does not make a lot
of sense for SmarterHR not to participate in the runtime error
detection. In fact, given free rein, I would write SmarterHR to do
nothing but throw an exception in the event that it is constructed or
assigned an HRESULT indicating an error
class SmarterHR
{
public:
SmarterHR(HRESULT inHResult)
{
if (HRESULT < 0)
throw HRESULT; // simplified for illustration
}
void operator=(HRESULT inHRESULT) const
{
if (HRESULT < 0)
throw HRESULT;
}
};
I would go still further and make SmarterHR a template class using an
enumerated non-type parameter. The enumeration could cover the types of
operations that the application performs. The enum value would be
included in the thrown exception, so that whatever function caught it
would have more information about the context in which the error
occurred.
Greg
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
OBQuiet Guest
|
Posted: Mon Jun 13, 2005 4:10 pm Post subject: Re: Question: Separating conversion on return from conversio |
|
|
Again my example wasn't clear enough.
HRESULT myMethod(){
SmartHR hr;
hr = SomeOtherMethod();
doSomethingThatAssumesSomeOtherMethodSucceeded();// oops
return hr;
}
It isn't a huge problem since most of the code we use does not follow
this example. It is much more likely that doSome...Succeeded() would
also return an HRESULT and assignment would catch the issue. I was just
hoping to find something that covered as many options as possible. And
my curiousity was set into gear.
But thanks for the ideas.
Otis
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|