3

When writing a code this way...

#include<bits/stdc++.h>
using namespace std;

class Node {
public:
    int data;

    Node(int data) {
        this->data = data;
    }
};

void display(const Node* &p){
    cout<<p->data<<endl;
}

int main(){
    Node *p = new Node(10);
    display(p);
    return 0;
}

I get the following error.

error: cannot bind non-const lvalue reference of type 'const Node*&' to an rvalue of type 'const Node*'

However, this works if the parameter const Node* &p of function display is changed to Node* &p.

Can someone explain to me how this works?

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • 3
    Don't use [#include](https://stackoverflow.com/questions/31816095/why-should-i-not-include-bits-stdc-h) – ShadowMitia Jul 14 '21 at 10:06
  • 1
    Why even use `const Node* &` instead of `const Node*` or `const Node&`? It seems that you do not want to modify where `p` points to in your `display` function. – Zaiborg Jul 14 '21 at 10:08
  • @Zaiborg , yes I don't want to modify the pointer p and it's pointed memory location in the `display` function. – Vishal Mahavar Jul 14 '21 at 11:43

2 Answers2

4

p is a Node * and can't be bound to const Node* & directly. It needs to be converted to const Node* firstly, which is a temporary, i.e. an rvalue, and can't be bound to lvaue-reference to non-const.

Changing to Node* & fixes the issue, p could be bound to Node* & directly without any implicit conversion.

BTW temporaries could be bound to lvalue-reference to const. Changing parameter type to const Node* const & works fine. LIVE

Or change from pass-by-reference to pass-by-value (the pointer itself) as const Node*. LIVE

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • So, the pointer was actually not being passed as a constant pointer but a pointer to a constant memory location? – Vishal Mahavar Jul 14 '21 at 11:56
  • 1
    @VishalMahavar Yes, (read from right to left) `const Node* &` is a reference to (non-const) pointer to `const` `Node`. – songyuanyao Jul 14 '21 at 11:58
  • But the conversion is from a non-constant memory location to a constant memory location. So, is the conversion prohibited or the reason to the error is something different? – Vishal Mahavar Jul 14 '21 at 12:02
  • @VishalMahavar No, `Node*` could be converted to `const Node*` implicitly, definately. The problem is the converted `const Node*` is a temporary, an rvalue which can't be bound to the reference. If the parameter type is a non-reference like `const Node*`, then it'll be fine. The converted `const Node*` will be passed to `display` (copied as parameter). – songyuanyao Jul 14 '21 at 12:07
  • so it is different from passing normal parameters, for example, a `int` can be passed into a function accepting parameters as `const int &`. But this doesn't work with pointers ig. – Vishal Mahavar Jul 14 '21 at 12:36
  • @VishalMahavar `const int &` is reference to `const`, passing `int` to `const int&` works fine. For pointer version it would be passing `Node*` to `Node* const&` (reference to const pointer to non-const), which works fine too. Note that it's different with `const Node*&` (reference to non-const pointer to const). (Yes I know it's confusing... :) ) – songyuanyao Jul 14 '21 at 12:51
1
const Node* &p
// p is a reference to a pointer to a constant 'Node'

And what you have is

Node *p
//  ^^ discarding the const qualifier is an error
display(p);
//      ^^ error

Probably the easiest fix here is to live up to the promise

const Node *p = new Node(10);
//^^^
display(p); // OK

void display(const Node*& p) is essentially the same as

void display(const Node** p)

And the standard has a good example of why initializing it with a (non-const) Node** is not allowed (n4659 [conv.qual]):

// [ Note: If a program could assign a pointer of type T** to a pointer of type const T** (that is, if line #1
// below were allowed), a program could inadvertently modify a const object (as it is done on line #2). For
// example,
int main() {
  const char c = 'c';
  char* pc;
  const char** pcc = &pc; // #1: not allowed
  *pcc = &c;
  *pc = 'C'; // #2: modifies a const object
}
// — end note ]
Andreas DM
  • 10,685
  • 6
  • 35
  • 62
  • The memory location was initially not constant but although the function was converting it into a `const Node` pointer I wonder why should it give a compilation error. I mean that the conversion is from non-constant to constant. – Vishal Mahavar Jul 14 '21 at 11:59