简体   繁体   中英

Passing a pointer to a variable or the address of a pointer to a variable result in the same behavior

Why both passing a pointer by value and passing it by its address both end up calling 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;
}

What is the &pointer_to_device doing? That is weird and shouldn't be allowed, the function isn't asking for a pointer to a pointer

I'm using MSVC2012

myfunc(&pointer_to_device) results in undefined behaviour.

Presumably it appears to work for you because you don't access any members of MyObj when calling or inside hello . To demonstrate this, try the same program with an updated version of MyObj

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

Your code is exhibiting undefined behavior .

Note that hello() is a non virtual method in a non-virtual class. The compiler will blindly generate a method call to MyObj::hello() and do so using whatever garbage happens to be in the pointer used for the call, passing it off as this .

This, by the way, gets especially nasty when you start accessing member variables in your "object" (which isn't an object in the first place).

It is the void* ptr that is masking the issue, void* can take in a pointer to pointer. If you replace that with MyObj* , the compiler will complain.

The second call to myfunc has undefined behaviour, because you cast a void** to a MyObj* and then dereference it. Undefined behaviour means anything can happen, including appearing to work correctly.

That is weird and shouldn't be allowed, the function isn't asking for a pointer to a pointer

It's asking for a void* which is a pointer that can point to anything, it can point to a MyObj (in the first case) or it can point to another void* (in the second case) so it is allowed, it's your responsibility to not do something like that. If you can't be trusted not to do that, then don't mess about with void* and casts.

The reason the code appears to work is that you don't access any member data of the object, so the compiler doesn't actually need to read any memory at *ptr2 . Your program is roughly equivalent to this (except that this does not have undefined behaviour):

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);
}

Notice how the value of ptr2 is never actually used, so it works OK. In your version the pointer is technically dereferenced by ptr2->hello() , but in practice the compiler doesn't need to dereference the variable to call a member function. It is still undefined behaviour though.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM