-1

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
}

EDIT: the following error cannot be reproduced and is hence deleted. This question is focused on the concept of reference-of-pointer instead of solving an issue

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:

Error cannot be reproduced

  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.
  1. 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.

  2. 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.

Power_tile
  • 578
  • 1
  • 6
  • 18
  • 3
    What compiler are you using? Also, your error messages do not match your code example. The error mentions a function named `test` being called on line 14 of main.cpp, but that is a clearly a different program to what you've shown. – paddy Oct 29 '21 at 02:55
  • The error message lists the erroneous code as `Foo(ptr)`... The code given is not the code that produced the error message. What is the exact type of `ptr` ?? – Michaël Roy Oct 29 '21 at 03:54
  • 1
    That code, with a trivial implementation of `Obj` added, does not produce that error. – molbdnilo Oct 29 '21 at 08:09
  • Sorry for the confusion. The test function I named was `test` instead of `Foo`. I replaced `test` to `Foo` after copying the compile error to SO, and made a mistake... – Power_tile Oct 29 '21 at 16:31
  • As for the compiler, I originally compiled my code using both clang++ and this [online GDB testing](https://www.onlinegdb.com/online_c++_compiler). However I cannot reproduce this error (???) in both environment now... I am editing this question into one without the error. – Power_tile Oct 29 '21 at 16:40
  • With the error removed, what exactly is the question? You have a goal, you implemented your goal, and it works now. You end with some thoughts, but no question. – JaMiT Oct 29 '21 at 21:58

2 Answers2

2

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();
}
cptFracassa
  • 893
  • 4
  • 14
  • *"I am not sure what your problem is"* -- this is typically a reason to avoid answering and instead request more information via a comment (or upvote such a comment if one already exists -- which is what I did). The purpose of Stack Overflow is to create a repository of questions and answers for future visitors. If a problem is not clearly identified in the question, it is unlikely that future visitors will be able to tell if the question relates to them. – JaMiT Oct 29 '21 at 13:17
-2

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) { ... }.

Dharman
  • 30,962
  • 25
  • 85
  • 135
SarvanZ
  • 90
  • 4
  • `const ObjPtr` is not the same as `const Obj *`. The former is a constant pointer to a non-constant object, while the latter is a non-constant pointer to a constant object. The OP specifically requested a pointer-to-const, which `ObjPtr` fails to deliver. – JaMiT Oct 29 '21 at 04:06
  • As @JaMiT wrote, by doing this, you make the pointer itself const - which means that it is impossible to reassign the pointer inside Foo. So with your "solution", the Foo function will no longer compile. – cptFracassa Oct 29 '21 at 08:21