0

为什么按值传递指针和按地址传递指针最终都调用 hello()?

class MyObj
{
public:
    void hello()
    {
        printf("hello");
    }
};

void myfunc(void *ptr)
{
    // I want the device
    MyObj* ptr2 = static_cast<MyObj*>(ptr);
    ptr2->hello();
}

int main()
{
    MyObj thisobj;

    void *pointer_to_device = &thisobj;

    myfunc(pointer_to_device);
    myfunc(&pointer_to_device);


    return 0;
}

&pointer_to_device 在做什么?这很奇怪,不应该被允许,该函数不要求指向指针的指针

我正在使用 MSVC2012

4

4 回答 4

2

myfunc(&pointer_to_device)导致未定义的行为。

MyObj大概它似乎对您有用,因为您在调用时或内部时不访问任何成员hello。为了证明这一点,请尝试使用更新版本的相同程序MyObj

class MyObj
{
    const char* str;
public:
    MyObj() : str("hello") {}
    void hello()
    {
        printf("%s\n", str);
    }
};
于 2013-09-05T19:46:14.520 回答
2

您的代码表现出未定义的行为

请注意,hello()这是非虚拟类中的非虚拟方法。编译器将盲目地生成一个方法调用,MyObj::hello()并使用用于调用的指针中的任何垃圾来执行此操作,并将其作为this传递出去。

顺便说一句,当您开始访问“对象”(首先不是对象)中的成员变量时,这会变得特别讨厌。

于 2013-09-05T19:48:11.650 回答
0

是 void* ptr 掩盖了问题, void* 可以接收指向指针的指针。如果你用 MyObj* 替换它,编译器会抱怨。

于 2013-09-05T19:46:42.883 回答
0

第二次调用 tomyfunc具有未定义的行为,因为您将 a强制void**转换为 aMyObj*然后取消引用它。未定义的行为意味着任何事情都可能发生,包括看起来正常工作。

这很奇怪,不应该被允许,该函数不要求指向指针的指针

它要求 a void*which 是一个可以指向任何东西的指针,它可以指向 a MyObj(在第一种情况下)或者它可以指向另一个void*(在第二种情况下)所以它是允许的,你有责任不做类似的事情那。如果你不能被信任不这样做,那么不要乱用void*和演员表。

代码似乎工作的原因是您不访问对象的任何成员数据,因此编译器实际上不需要在*ptr2. 您的程序大致相当于这个(除了它没有未定义的行为):

void hello(MyObj* unused)
{
  printf("hello");
}

void myfunc(void *ptr)
{
    // I want the device
    MyObj* ptr2 = static_cast<MyObj*>(ptr);
    hello(ptr2);
}

int main()
{
    MyObj thisobj;

    void *pointer_to_device = &thisobj;

    myfunc(pointer_to_device);
    myfunc(&pointer_to_device);
}

请注意ptr2实际从未使用过的值,因此它可以正常工作。在您的版本中,指针在技术上被取消引用ptr2->hello(),但实际上编译器不需要取消引用变量来调用成员函数。尽管如此,它仍然是未定义的行为。

于 2013-09-05T19:48:26.920 回答