将指针传递给变量或指向变量的指针的地址会导致相同的行为

时间:2013-09-05 19:39:49

标签: c++ visual-c++ visual-studio-2012

为什么通过值传递指针并通过其地址传递它们都会调用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;
}

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

我正在使用MSVC2012

4 个答案:

答案 0 :(得分:2)

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

据推测,它似乎适合您,因为您在通话时或MyObj内无法访问hello的任何成员。要证明这一点,请尝试使用更新版MyObj

的相同程序
class MyObj
{
    const char* str;
public:
    MyObj() : str("hello") {}
    void hello()
    {
        printf("%s\n", str);
    }
};

答案 1 :(得分:2)

您的代码显示未定义的行为

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

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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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

  

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

它要求void*这是一个可以指向任何东西的指针,它可以指向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()取消引用,但实际上编译器不需要取消引用该变量来调用成员函数。但它仍然是未定义的行为。