I am looking at something that I discovered in an old code base, and I am pretty confused.
Here is a function definition:
void vUpdateSequenceDetailsAndIncrement(
const CallEvent& roCPEvent,
const CallInfo& roCallInfo,
BOOL bCreationEvent);
Here it is being called:
vUpdateSequenceDetailsAndIncrement(roCPEvent, NULL, FALSE);
Here NULL is being passed directly to the reference parameter roCallInfo
. This function eventually calls:
vTimeChange(*pSeqDetails, roCPEvent, roCallInfo);
which is defined:
void vTimeChange(const SequenceDetails& roSequenceDetails,
const 开发者_如何学JAVACallEvent& roCPEvent,
const CallInfo& roCallInfo)
Again passing the possibly NULL value to roCallInfo
. I thought that NULL could not be passed as a reference? Does anyone know if VC++ 4.x had some kind of problem which made this kind of code okay? If NULL can be passed as a reference then what happens when in vTimeChange something like this happens:
roCallInfo.getCallStartTime();
Is that not a dereference of NULL in the same way as if I were to do
CallInfo * info = NULL;
info->getCallStartTime();
? I'll probably put a guard in there anyways and let the compiler remove it if unnecessary, but I'd love to get to the bottom of how this is happening!
Thanks.
Depends on how NULL is defined in VC 4.2
If it is just
#define NULL 0
then you are actually getting this under the hood:
vUpdateSequenceDetailsAndIncrement(roCPEvent, CallInfo(0), FALSE);
and reference of temp var of type CallInfo is passed to the function (if CallInfo has compatible ctor)
I thought that NULL
could not be passed as a reference?
A valid reference can't be null, but an invalid one can be null.
What you have here is an Invalid Reference.
The fact that a reference can't be null does not mean that references are somehow safer than pointers, as you see here in this case. There can be many ways in which an program may lead to Invalid References, Your code is one such example.
Reference Wikipedia:
There are also de facto ways that a reference
can start out invalid
. Because a reference is usually implemented as an underlying pointer, initializing a reference on a pointer-dereferencing expression, will usually be implemented by the compiler as a simple assignment from the pointer to the underlying pointer of the reference. Thus, if you have a NULL
pointer or a pointer pointing to an invalid location in memory, you will de facto have a reference that points to NULL or an invalid location. C++ purists would argue that, technically, dereferencing a NULL or invalid pointer leads to undefined behavior anyway, so this does not violate the assertions above that a reference cannot be null or point to arbitrary places in memory. However, this ignores the fact that in this case, the underlying implementation simply performs an "assignment", and there is no access of the memory location involved, so this initialization of the reference usually does not cause problems, and programmers must be aware of the possibility of a de facto "invalid" reference in a real program.
Using the Invalid Reference roSequenceDetails
would eventually lead to an Undefined Behavior.
The expression *pSeqDetails
results in undefined behavior if pSeqDetails
is null. Anything can happen. Most implementations don't make any particular checks; your code will seem to work until you do something that actually requires the object, then it will fail. But an implementation could cause it to fail immediately.
精彩评论