Home > Software engineering >  How can I take a reference of a pointer in C ?
How can I take a reference of a pointer in C ?

Time:10-29

I am passing in a reference to a pointer variable into a function. The function will do something and point the pointer variable to some object. Code:

int Foo(Obj* &ptr) {
  // do something...
  ptr = some_address;
  return return_value;
}

int main() {
  Obj* p = nullptr;
  int ret = Foo(p);
  // do something with ret
  p->DoSomething();
}

However, things get trickier if I want to pass a reference to a pointer to const. I would like the pointer variable itself to be changed (hence the reference), but I don't want the pointed Obj instance to change using this pointer. In my imagination, it should be something like:

int Foo(const Obj* &ptr) {
  // do something...
  ptr = some_address;
  return return_value;
}

int main() {
  const Obj* p = nullptr;
  int ret = Foo(p);
  // do something with ret
  p->DoSomething(); // this should only work when DoSomething() is const method
}

C gives this compile error:

main.cpp:22:10: error: cannot bind non-const lvalue reference of type ‘const Obj*&’ to an rvalue of type ‘const Obj*’
   22 |     Foo(ptr);
      |         ^~~
main.cpp:14:23: note:   initializing argument 1 of ‘void test(const Obj*&)’
   14 | int Foo(const Obj* &ptr) {
      |         ~~~~~~~~~~~~^~~

Some thoughts:

  1. I believe this error is shown when I am trying to pass in an "unnamed variable" into a reference parameter. In this case I am passing the variable ptr, which shouldn't be an issue.
  2. ptr is passed in as a parameter because the function has a useful return value. Setting ptr is more like a side-product of this function, where the caller can choose to ignore or use.
  3. I can also try using Obj** as the parameter, which is passing by pointer instead of passing by reference. This works when a const Obj** is passed as parameter. I am just wondering what will be the case if the parameter is passed by reference.

CodePudding user response:

I am not sure what your problem is, as the error code given does not match your code.

Your second example with int Foo(const Obj* &ptr) works exactly as intended, and compiles fine if you make DoSomethingconst.

To comment your three thoughts:

  1. If you const things correctly, the error goes away.
  2. I really, really dislike such out-paramteres. It is much cleaner to return a struct or a pair of int and pointer. That way the caller can write const auto[ret, p] = Foo(); and not have to explicitely declare the pointer that you may not want to use.
  3. Passing pointers to pointers is C-style, due to lack of references, and just make the code harder to read, with no benefit.

Below is slightly modified code that compiles fine, with a better Foo too, as mentioned in my answer to 2.:

#include <utility>

struct Obj
{
    void DoSomething() const;
};

// This is ugly of course, used just to have a valid ptr to return
Obj global;

int Foo(const Obj* &ptr) {
  // do something...
  ptr = &global;
  return 5;
}

std::pair<int, const Obj*> BetterFoo()
 {
  // do something...
  return {5, &global};
}

int main() {

  const Obj* p1 = nullptr;
  int ret1 = Foo(p1);

  const auto[ret2, p2] = BetterFoo();

  p1->DoSomething(); 
  p2->DoSomething();
}

CodePudding user response:

One way to deal with this situation is to use typedef or using. For example, using ObjPtr = Obj*; now the function would be int Foo(const ObjPtr& ptr) { ... }.

  • Related