Jump to content

  • Log In with Google      Sign In   
  • Create Account

Pointer to pointer question


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
6 replies to this topic

#1 noatom   Members   -  Reputation: 785

Like
0Likes
Like

Posted 12 January 2014 - 11:49 AM

Take the directx 9 CreateIndexBuffer function,these are the args:


HRESULT CreateIndexBuffer(
  [in]           UINT Length,
  [in]           DWORD Usage,
  [in]           D3DFORMAT Format,
  [in]           D3DPOOL Pool,
  [out, retval]  IDirect3DIndexBuffer9 **ppIndexBuffer,
  [in]           HANDLE *pSharedHandle
);

What I did,was: I created a pointer to pointer:

IDirect3DIndexBuffer9 **pp;

 

And used it in the function call.But I get an exception,if I change it,so I create only a pointer(not a pointer to pointer) variable:

IDirect3DIndexBuffer9 *pp;

 

and pass it as an argument in the form &pp,it works.

 

Why?



Sponsor:

#2 Ectara   Crossbones+   -  Reputation: 3059

Like
0Likes
Like

Posted 12 January 2014 - 12:07 PM

By taking the address of pp with &pp, you are creating a pointer to pp's type. If pp is a pointer to a pointer, then taking its address results in a pointer to a pointer to a pointer. If pp is a pointer, then taking its address produces a pointer to a pointer, which is what you want. Output parameters like that tend to accept a pointer to what it is going to return. In this case, it seems to be returning a pointer, and wants a pointer to a pointer so that it can dereference it later, assign the pointer value, and you get it after calling the function by passing the address of your pointer variable.

Hope that helps.


Edited by Ectara, 12 January 2014 - 12:08 PM.


#3 noatom   Members   -  Reputation: 785

Like
0Likes
Like

Posted 12 January 2014 - 12:16 PM

you got it wrong,when I had IDirect3DIndexBuffer9 **pp,i simply passed it as pp,not &pp.



#4 Samith   Members   -  Reputation: 2310

Like
0Likes
Like

Posted 12 January 2014 - 12:24 PM

A common method for returning multiple values in C++ is to "return" values by writing to parameters that were passed by reference. In your case, CreateIndexBuffer returns an HRESULT as the function's return value, but also returns a IDirect3DIndexBuffer9* via a parameter passed by reference. In order to pass a IDrect3DIndexBuffer9* by reference, the function must either take a IDirect3DIndexBuffer*& (a C++ reference to a pointer) or take a IDrect3DIndexBuffer** (a pointer to a pointer). You can imagine the function CreateIndexBuffer is implemented like this:

// very pseudo code follows

HRESULT CreateIndexBuffer(
  /*[in]*/           UINT Length,
  /*[in]*/           DWORD Usage,
  /*[in]*/           D3DFORMAT Format,
  /*[in]*/           D3DPOOL Pool,
  /*[out, retval]*/  IDirect3DIndexBuffer9 **ppIndexBuffer,
  /*[in]*/           HANDLE *pSharedHandle
)
{
    /* do some d3d9 stuff */
    IDirect3DIndexBuffer9 *pBuffer = new ConcreteDirect3DIndexBuffer9(/*etc*/);

    if (pBuffer != NULL) {
        // now assign pBuffer to *ppIndexBuffer to 'return' this value
        *ppIndexBuffer = pBuffer;  // dereference ppIndexBuffer and set its value
        return S_OK;
    }

    return E_FAIL;
}

Now consider what happens when you call CreateIndexBuffer two different ways:

IDirect3DIndexBuffer9 **pp;
CreateIndexBuffer(etc, pp);  // CreateIndexBuffer will dereference pp, but pp is an uninitialized variable, and the dereference will fail


// if you call it like this
IDrect3DIndexBuffer9 *p;
CreateIndexBuffer(etc, &p);  // CreateIndexBuffer will dereference &p, giving just p, which can then be written to

Edited by Samith, 12 January 2014 - 12:24 PM.


#5 Ectara   Crossbones+   -  Reputation: 3059

Like
0Likes
Like

Posted 12 January 2014 - 12:27 PM

you got it wrong,when I had IDirect3DIndexBuffer9 **pp,i simply passed it as pp,not &pp.

Even so, the latter half of my post applies. The function is trying to dereference the pointer to write to what it points to. If you are passing an uninitialized pointer to a pointer, then the program will crash when it tries to write to it.



#6 SeanMiddleditch   Members   -  Reputation: 7192

Like
0Likes
Like

Posted 12 January 2014 - 02:06 PM

you got it wrong,when I had IDirect3DIndexBuffer9 **pp,i simply passed it as pp,not &pp.

 

Think of what is wanted conceptually.  The call wants to give you a pointer to IDirect3DIndexBuffer9.  It needs the address of a pointer in order to modify it.  Because it will modify the pointer at that address, you must give it the address of a real pointer.

 

You need a pointer:

IDirect3DIndexBuffer9* indices;

Done.  Now you need a function to modify that pointer.  Not modify the object that the pointer refers to (which currently is some random location in memory), but the pionter itself.  So you need the address of that pointer, which is stored in a pointer to the thing you're taking the address of.  The address of a pointer is stored in a pointer to a pointer.

IDirect3DIndexBuffer9** indices_address = &indices;

Now you can pass that to the function.  It can dereference that pointer-to-pointer and hence be able to modify the location in memory that the original pointer refers to.  That's what it wants to do.  It wants to create and object and then make your original pointer refer to that object, hence it needs to modify the pointer itself (and needs its address in memory to do so).

 

Pointers refer to addresses.  To modify a specific value in memory, you need its address.  To modify what a pointer refers to, you need its address.  Don't even start thinking about syntax or variables until you think about the concept of what you're trying to do.  Then you can work forward to figure out the correct syntax and interfaces to achieve that goal, rather than guessing at syntax and then having to work backward to figure out why it didn't work.



#7 L. Spiro   Crossbones+   -  Reputation: 14272

Like
0Likes
Like

Posted 12 January 2014 - 08:48 PM

Part 1

 

The method wants to give you back a pointer to an object.

An IDirect3DIndexBuffer9 *.

 

Internally it is going to allocate an object and set the pointer you give it to that pointer.

 

Look at this:

 

void GiveYouMyPointer( IDirect3DIndexBuffer9 * _pd3dib9Out ) {
    IDirect3DIndexBuffer9 * pd3dib9Allocated = new IDirect3DIndexBuffer9();
    _pd3dib9Out = pd3dib9Allocated;
}
 
IDirect3DIndexBuffer9 * pd3dib9IndexBuffer = NULL;
GiveYouMyPointer( pd3dib9IndexBuffer );

 

What is pd3dib9IndexBuffer after this?

The answer is NULL.  GiveYouMyPointer() changed a copy of your pointer.  It didn’t actually make your pointer point to anything else.

 

There are 2 ways to do that correctly:

void GiveYouMyPointer( IDirect3DIndexBuffer9 * &_pd3dib9Out ) {
    IDirect3DIndexBuffer9 * pd3dib9Allocated = new IDirect3DIndexBuffer9();
    _pd3dib9Out = pd3dib9Allocated;
}

Now your pointer is passed as a reference, so changing it inside GiveYouMyPointer() actually changes your pointer from NULL to something else.

 

void GiveYouMyPointer( IDirect3DIndexBuffer9 ** _pd3dib9Out ) {
    IDirect3DIndexBuffer9 * pd3dib9Allocated = new IDirect3DIndexBuffer9();
    (*_pd3dib9Out) = pd3dib9Allocated;
}

This is exactly the same as passing by reference, except it requires a manual dereference inside GiveYouMyPointer().  Either way it is able to modify the pointer you actually passed it from NULL to something else.

 

 

This is what is happening inside those methods and why you have to pass things that way.  Microsoft just chose to use 2 pointers instead of a reference.

 

 

Part 2

So why does this not work?

IDirect3DIndexBuffer9 ** ppd3dib9IndexBuffer = NULL;
GiveYouMyPointer( ppd3dib9IndexBuffer );

 

 

Because:

void GiveYouMyPointer( IDirect3DIndexBuffer9 ** _pd3dib9Out ) {
    IDirect3DIndexBuffer9 * pd3dib9Allocated = new IDirect3DIndexBuffer9();
    (*_pd3dib9Out) = pd3dib9Allocated; // ERROR: First pointer points to NULL/garbage.  Bad dereference.
    // Same as (*NULL) = pd3dib9Allocated;
}

 

 

L. Spiro


It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS