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:
- 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. ptr
is passed in as a parameter because the function has a useful return value. Settingptr
is more like a side-product of this function, where the caller can choose to ignore or use.- I can also try using
Obj**
as the parameter, which is passing by pointer instead of passing by reference. This works when aconst 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 DoSomething
const.
To comment your three thoughts:
- If you const things correctly, the error goes away.
- 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. - 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) { ... }
.