11

In simple words I have a simple pointer:

int* a;

now, I would like to change value of this pointer. I want to do this in a function. Function assures, that it will not change object, that pointer points to, but will change a pointer itself. This is why I would like this function to take argument like: non-const reference (because value of pointer will be changed) to the non-const pointer(pointer itself can be changed) pointing to const object (function assures, that object, that pointer points to will not be changed).

The simplest function would be:

void function(const int*& a){
    a = 0;
}

but when I try to call this function:

int main(){
    int* a;
    function(a);
    return 0;
}

Compiler is unhappy and says:

invalid initialization of non-const reference of type 'const int*&' from an rvalue of type 'const int*' function(a);

I cannot quite understand this error, as for me there is no rvalue involved (I am passing a reference to object, that already exists on the stack.)

Question is, how can I do it properly?

Example can be found here: https://ideone.com/D45Cid


EDIT:

It was suggested, that my question is simillar to the Why isn't it legal to convert "pointer to pointer to non-const" to a "pointer to pointer to const"

My question is different as I do not use pointer to pointer I use only pointer to object/value and store reference to it, therefore situation like in the answer to that question:

const char c = 'c';
char* pc;
const char** pcc = &pc;   // not allowed
*pcc = &c;
*pc = 'C';                // would allow to modify a const object

Is impossible in my case, as I cannot dereference the top level pointer (I do not have such a pointer).

Moreover I questioned about nice and clean solution to this problem, which is not covered in a question

Community
  • 1
  • 1
DawidPi
  • 2,285
  • 2
  • 19
  • 41
  • 1
    i am not sure if you can mix up pointer and a reference. Well it's c++ you should, but please don't. Nobody will understand your code! – hr0m Mar 30 '16 at 07:20
  • @Holt I cannot do this. This is simple example, but in real code later I am doing operations on this object, so I cannot declare pointer as const – DawidPi Mar 30 '16 at 07:21
  • @hr0m Pointer to the pointer is better, than pointer to reference? Those in my opinion have different meanings. – DawidPi Mar 30 '16 at 07:24
  • Yes but think of someone (you) in two weeks looking at code. If i see a reference, i automatically make assumptions how to use it and with that what is it. One could argue whether it is or is not a good coding style, but you have to admit, that code is not nice. – hr0m Mar 30 '16 at 07:26
  • A doublepointer is clear to everyone, a reference to a pointer is just a weird think. – hr0m Mar 30 '16 at 07:27
  • 3
    @hr0m I don't see what's wrong with a reference to a pointer. If you want to take in a pointer and modify it then a reference to a pointer is the natural way to do so. Taking a pointer to the pointer you want to modify implies that it could be null, which is not the case with a reference. – TartanLlama Mar 30 '16 at 07:28
  • @TartanLlama Yeah, you are probably right. Maybe it is just me, because i never used it that way. What you could do is: `a = func(a);` A call by value wich returns the value. Much more clearer to everyone. Has the nice side effect that your a in main doesn't change, till the function is finished. – hr0m Mar 30 '16 at 07:34
  • Internally, a reference in much the same of a const pointer, so the explaination from the proposed duplicate apply here. – Serge Ballesta Mar 30 '16 at 08:10
  • @SergeBallesta I am not going to argue about this. Surely references are simillar to ponters, but answer there didn't explain my compiler error neither offered any way to go around this problem. Delete this question if you want. – DawidPi Mar 30 '16 at 08:35
  • 1
    @hr0m: Just because you are unfamilliar wiht something doesn't mean it is bad practice. And a reference of a pointer is something that should really be understood by any c++ programmer. In particular, I don't see, why a double pointer should be more understandable. – MikeMB Mar 30 '16 at 08:46
  • @MikeMB yeah that's what i said afterwards. I learned something. That's why we are here. I still believe that my solution `a = func(a);` where func is const int* or int* is most understandable and will actually work. – hr0m Mar 30 '16 at 08:54
  • @hr0m: No argument there – MikeMB Mar 30 '16 at 08:55

2 Answers2

9

I cannot quite understand this error, as for me there is no rvalue involved (I am passing a reference to object, that already exists on the stack.)

int* and const int* are different things. When you pass a of type int* to function(const int*&), it need to be implicitly casted to const int* firstly, which is temporary, i.e. rvalue, and couldn't be bound to non-const referece. That's why compiler complains.

Question is, how can I do it properly?

You could change the type of a or the parameter type of function() to make them match exactly (might be const int* if you won't change the value pointed by the pointer), to avoid the implicit conversion and temporary variable. Or as @TartanLlama suggested, return the new value of pointer from function().

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • 3
    Another option would be to return the new value of the pointer, maybe in a struct or pair if there is already a return value. – TartanLlama Mar 30 '16 at 07:30
2

I'm not quite sure what it is you want to achieve.

This piece of code might help you, though. It should point to how you can do what you want.

#include <iostream>

using namespace std;

int A = 1;
int B = 2;
int C = 3;

void change_pointer(int*& a){
    // your pointer will point to B
    a = &B;
}

void change_value(int* const& a) {
    // the reference to pointer is constant, but not the value
    // a=&C; wouldn't work
    *a = C;
}

int main(){
    int* a;
    // at this point a is an undefined pointer to an int
    // *a is unallocated space

    a=&A; // you initialize the pointer with an other pointer
    cout << "*a = " << *a << ", A = " << A << ", B = " << B << ", C = " << C << endl;

    change_pointer(a); // makes 'a' point to B
    cout << "*a = " << *a << ", A = " << A << ", B = " << B << ", C = " << C << endl;

    change_value(a); // changes the value pointed by a to C (in the process modifying the value of B)
    cout << "*a = " << *a << ", A = " << A << ", B = " << B << ", C = " << C << endl;

    return *a;
}

EDIT: In answer to TartanLlama's comment.

The only way I can see to work with a "non const ref" to a "non const pointer" to a "const int" is by using typedef :

#include <iostream>

using namespace std;

typedef const int const_int_t;

const_int_t A = 1;
const_int_t B = 2;

void change_pointer(const_int_t*& a){
    // your pointer will point to B
    a = &B;
}

int main(){
    const_int_t* a;

    a=&A; // you initialize the pointer with an other pointer
    cout << "*a = " << *a << ", A = " << A << ", B = " << B << endl;

    change_pointer(a); // makes 'a' point to B
    cout << "*a = " << *a << ", A = " << A << ", B = " << B << endl;

    return *a;
}
  • 1
    This isn't what OP wants. He wants a non-const reference to a non-const pointer to a const `int`. – TartanLlama Mar 30 '16 at 09:41
  • @TartanLlama: thanks for clearing up things for me. I added a solution using typedef. – Stéphane Ch. Mar 30 '16 at 11:50
  • 1
    That's not what he wants either, and the typedef doesn't add anything. The problem is getting a non-const reference to a non-const pointer to a const `int` from a non-const poirter to non-const `int` . – TartanLlama Mar 30 '16 at 12:49