1

I'm reading an example of ffmpeg decoding and it has the address of a pointer being passed to a function:

static AVBufferRef *hw_device_ctx = NULL;


if ((err = av_hwdevice_ctx_create(&hw_device_ctx, type,
                                  NULL, NULL, 0)) < 0) {

What's the point of passing the address of a pointer as an argument?

I understand that when we pass the pointer itself, if the pointer has address 0x123456, then the function is going to be able to modify what's the object that is in this address. But when I pass the address of a pointer, I'm passing the address of where this pointer number is allocated?

If I understood right, I'm passing the address of the variable that stores 0x123456? Why the function needs it?

Also, suppose that I want to store hw_device_ctx in a unique_ptr like this:

std::unique_ptr<AVBufferRed> hw_pointer;

How can I pass it to av_hwdevice_ctx_create? Because I get an error when I do

av_hwdevice_ctx_create(&hw_pointer.get(),...

It says:

expression must be an lvalue or a function designator
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Guerlando OCs
  • 1,886
  • 9
  • 61
  • 150
  • 2
    Read the parameter documentation: https://ffmpeg.org/doxygen/3.2/hwcontext_8c.html#a21fbd088225e4e25c4d9a01b3f5e8c51 – user202729 Aug 16 '19 at 06:07
  • Also note that you need to call a special function to destroy it, so your normal unique_ptr won't work. – user202729 Aug 16 '19 at 06:08
  • The context-create function wants to assign a single pointer to the `AVBufferRef *` in the calling function, so it needs to be passed a pointer to that pointer to be able to make the change. – Jonathan Leffler Aug 16 '19 at 06:12
  • Related: [Passing reference to pointers in C++](https://stackoverflow.com/questions/823426/passing-references-to-pointers-in-c) – francesco Aug 16 '19 at 06:12
  • @user202729 thanks, I'm using a custom deleter, I just didn't add in the example – Guerlando OCs Aug 16 '19 at 06:16

4 Answers4

1

When you pass a pointer, you pass pointer by value. So you can modify the variable your pointer points to but not the pointer itself.

If you needed to modify the pointer itself (e.g. point to somewhere else) you pass it by reference or pointer to pointer.

The reason the reference of unique_ptr doesn't work is because you are trying to get a reference of a temporary which will imediately die. If the function accept a const ref it would work but evidently it is not what you are trying to achieve.

You should NOT modify a pointer which is managed by a smart pointer. You can pass the pointer to the smart pointer after function call.

Oblivion
  • 7,176
  • 2
  • 14
  • 33
1

It needs that for the same reason that a function that wants to modify an int needs to be passed a pointer (or reference) to a modifiable int.

That is, your situation is the same as

int f() { return 0; }
void foo(int* x) { *x = 1; }
...
foo(&f());

If you want to manage lifetime with a unique_ptr, let the function create the object first and then hand over ownership of it to the unique_ptr:

AVBufferRef *hw_device_ctx = NULL;
if ((err = av_hwdevice_ctx_create(&hw_device_ctx, type,
                                  NULL, NULL, 0)) < 0) {
   ..
}
else
{
    std::unique_ptr<AVBufferRed> hw_pointer(hw_device_ctx);
    ...
}
molbdnilo
  • 64,751
  • 3
  • 43
  • 82
0

If I understood right, I'm passing the address of the variable that stores 0x123456?

Yes, you understood it right. You are passing the address of a variable that holds another address.

Why the function needs it?

In most cases a function declares a pointer to pointer as a parameter when the argument when passed to this function is normally a pointer by design and the function needs to modify the argument itself (in your example, the variable that holds 0x123456).

How can I pass it to av_hwdevice_ctx_create? Because I get an error when I do

You shouldn't. This functions lets the caller the responsibility to free the memory after usage, however if you really want to do this, you can assign a variable with unique_ptr.get() and then pass the address of this new variable (which will break the whole idea of the smart pointer you are using - in this particular case you should use a raw pointer).

andresantacruz
  • 1,676
  • 10
  • 17
0

As you wrote, when you pass the pointer to something, the function can modify the data in the object/memory that the pointer points to. But you, i.e. your application, has to allocate the memory itself.

When you pass the address of a pointer, the function that is called can allocate the memory itself and return the newly allocated object or memory through the pointer.
Btw.: Read the documentation if your application has to free the memory again!

Rene
  • 2,466
  • 1
  • 12
  • 18
  • Thanks, I kow that I need to free the alocated memory, I'm using a custom unique_ptr deleter for it, I just didn't add in the example. But do you know how to I pass the a reference to a pointer when it is inside a unique_ptr? As you can see in my question, I can't do `&myUniquePtr.get()` – Guerlando OCs Aug 16 '19 at 06:17
  • @GuerlandoOCs you could assign the return of myUniquePtr.get() inside a new variable, and then pass to the function the address of this new variable. However I think it makes more sense to use a raw pointer is this case. – andresantacruz Aug 16 '19 at 06:24
  • Yes, use a raw pointer first, and only when you get the pointer back assign it to `std::unique_ptr()` to make sure it is deleted. – Rene Aug 16 '19 at 06:32