7

我需要为回调函数编写代码(它将在 ATL 中调用,但这并不重要):

HRESULT callback( void* myObjectVoid )
{
    if( myObjectVoid == 0 ) {
       return E_POINTER;
    }
    CMyClass* myObject = static_cast<CMyClass*>( myObjectVoid );
    return myObject->CallMethod();
}

这里void*保证是指向的指针CMyClass,所以static_cast是合法的。我担心的是代码必须尽可能可移植(至少到较新版本的 Visual C++)。因此,为了超级偏执,我也倾向于检查CMyClass*指针 - 我的意思是如果它结果为空怎么办?

    if( myObjectVoid == 0 ) {
       return E_POINTER;
    }
    CMyClass* myObject = static_cast<CMyClass*>( myObjectVoid );
    if( myObject == 0 ) {
       return E_POINTER;
    }

第二次检查是否合理?是否可以static_cast将非空指针转换为空指针?

4

4 回答 4

7

如果您在不同偏移量的对象部分之间进行转换,则 static_cast 可以更改指针值:

class A{ int x; }; class B{ int y; };
class C : A,B {};

C *c=new C(); 

B *b=c; 
// The B part comes after the A part in C. Pointer adjusted

C *c2=static_cast<C*>(b); 
// Pointer gets adjusted back, points to the beginning of the C part

However, "The null pointer value (4.10) is converted to the null pointer value of the destination type." (5.2.9-8), i.e. if c is NULL, then b is also NULL (and not adjusted) and thus c2 is set to NULL. The whole thing means: if static casting a non-NULL myObjectVoid yields NULL, then the value of myObjectVoid was obtained by circumventing the type system somehow. And it means, that the compiler might throw your second check away because "it can't happen anyway".

于 2010-08-12T15:28:53.120 回答
6

不,如果指针引用了一个有效的对象,并且转换是有效的,那么结果也将引用一个有效的对象,所以它不会为空。如果其中任何一个无效,则代码不正确并且结果未定义。因此,有效使用给出 null 结果的唯一方法是从 null 开始。

在对象指针和 void 指针之间转换的特定情况下,标准有这样的说法(5.2.9/10):

将“指向对象”类型的值转换为“指向void”并返回到原始指针类型的值将具有其原始值。

而这个 (4.10/3)

将“指向 T 的指针”转换为“指向 T 的指针”的结果指向 Tvoid类型的对象所在的存储位置的开始

所以原始对象指针和最终对象指针将是相同的,并且void当且仅当对象指针是时,指针才会为空。

于 2010-08-12T15:20:50.917 回答
0

static_cast应该对指针进行的唯一更改是字对齐。因此,理论上,myObjectVoid指向内存中的最后一个字节,它可能会“对齐”为 0,但我不认为这是一个现实的问题。

于 2010-08-12T14:55:31.257 回答
0

No, the second check is not reasonable. It is not possible for static_cast to turn a non-null pointer into a null pointer. The only thing static_cast may change about the supplied value in your case (being a pointer) is to adjust the address. Otherwise it's strictly concerned with advising the rest of the compiler's type analysis that the result of the expression should be treated as the target type. For a pointer, that means that dereferencing finds the right address within the target object, and that increment and decrement strides are appropriate to the type's size.

于 2010-08-12T15:33:35.657 回答