7

Every time I try to compile my code I get error:

cannot convert parameter 1 from 'int *' to 'int *&'

The test code looks like this:

void set (int *&val){
   *val = 10;
}

int main(){
   int myVal;
   int *pMyVal = new int;
   set(&myVal); // <- this causes trouble
   set(pMyVal); // <- however, this doesn't
}

I'd like to call that function in a single shot without creating a pointer somewhere only to pass it. And as pointers don't have constructors, something like this can't be done: set(int*(&myVal));

Is there any other way to pass a pointer by reference without needing to create a temporary variable?

Edit: By the way I know why the code fails to compile (I'm just passing the address which is possibly int and not an actual pointer). The question is how else can it be done.

Kevin
  • 16,549
  • 8
  • 60
  • 74
Raven
  • 4,783
  • 8
  • 44
  • 75
  • If you don't want to create a pointer, why do you require the function to take a pointer (by reference)? Why not `set (int &v){v=10;}`? – Beta Sep 05 '11 at 12:57
  • Because my class is storing value, but this value is then passed as pointer to another class which stores this pointer. This pointer must be set by reference to pointer argument in function that does it, because otherwise the passed pointer isn't really pointing to value, but to it's copy. And before setting this pointer I don't want to create temporary pointer just to be able to pass it.. That's why I didn't introduce actual problem, but only that which resembles my it and is way more easy. – Raven Sep 05 '11 at 13:10

5 Answers5

16

A reference to non-const cannot bind to an rvalue. The result of the & operator is an rvalue. Take a look at the difference between lvalues and rvalues or read a good C++ book.

Also, in your context, you don't need to pass by reference. The following is OK as well:

void set (int *val){
   *val = 10;
}

The reference would be needed if you were to do something like this;

void set (int*& val){
   val = new int; //notice, you change the value of val, not *val
   *val = 10;
}
Kevin
  • 16,549
  • 8
  • 60
  • 74
Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
  • so `int* const& p` is reference to constant pointer to integer, and so it can be assigned rvalue, right? – Raven Sep 05 '11 at 13:27
  • 2
    @Raven: Yes, that is correct. But no need to pass built-in types by reference to const. It's less effective than passing by value. For User-Defined Types, it's better to pass by reference-to const – Armen Tsirunyan Sep 05 '11 at 13:30
2

&myval is an rvalue (of type int*), because it's a temporary. It's a pointer, but you cannot modify it, because it's just created on the fly. Your function set however requires a non-const reference, so you cannot pass it a temporary.

By contrast, pMyVal is a named variable, thus an lvalue, so it can be passed as a non-constant reference.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • I'd say `&myval` is of type `int * const &`. – starblue Sep 05 '11 at 13:00
  • Sorry, but this is incorrect and misleading in many ways. For one, `const int * &` is a "reference to a pointer to const int", not a "reference to constant pointer". Second, there is a distinction between references to const and rvalues (rvalues _don't_ have type `const T&`). Third, an object need not be named to be a lvalue. – jpalecek Sep 05 '11 at 13:02
  • @jpalecek: I didn't say lvalues have to be named objects, I said that this named object is an lvalue. Not all cats... – Kerrek SB Sep 05 '11 at 13:03
  • `&myval is of type int * const &` is plain wrong. `&myval` is an rvalue of type `int*` – Armen Tsirunyan Sep 05 '11 at 13:04
  • @Armen: Yet you cannot say `&myval = (int*)0;`, which you could if it were an `int*`, non? – Kerrek SB Sep 05 '11 at 13:05
  • @Kerrek SB: Indeed, you cannot. That's because it's an rvalue, not because it's a reference to const pointer – Armen Tsirunyan Sep 05 '11 at 13:06
  • 1
    @Kerrek: ad named objects: I find your formulation misleading, it indicates that "lvalues" are synonymous to "named objects". You could have written "... is a named variable (which is an lvalue) ..." or something. To the other issue, read what Armen wrote. – jpalecek Sep 05 '11 at 13:10
  • @Kerrek SB: To be extremely picky, I would add that a non-const reference is a misnomer, since it is a reference to non-const :) – Armen Tsirunyan Sep 05 '11 at 13:14
  • @Armen: That's true, but since all references are "const", i.e. not rebindable, I think "const/non-const reference" is common enough parlance - but of course you're right. – Kerrek SB Sep 05 '11 at 13:32
0

A very simple example can be found in this place. http://markgodwin.blogspot.de/2009/08/c-reference-to-pointer.html

curious_beast
  • 85
  • 1
  • 9
0

You can see the following sample code:

#include <iostream>
using namespace std;

void change(int*& ptr) {
    cout << endl;
    cout << "==================change(int*& ptr)====================" << endl;
    cout << "    &ptr = " << &ptr << endl;
    cout << "    ptr  = " << ptr << endl;
    cout << "=======================================================" << endl;
    cout << endl;
    *ptr *= *ptr;
}

int main(void) {
    int* ptrNumber = new int(10);

    cout << endl;
    cout << "&ptrNumber = " << &ptrNumber << endl;
    cout << "ptrNumber = " << ptrNumber << endl;
    cout << ">>> *ptrNumber = " << *ptrNumber << endl;
    change(ptrNumber);
    cout << "<<< *ptrNumber = " << *ptrNumber << endl;
}

I installed Cygwin and used g++ to compile the above source code, binary file is out_pointer.exe. Executing out_pointer.exe, output is as follows:

$ ./out_pointer.exe

&ptrNumber = 0x28ac3c
ptrNumber = 0x800102c0
>>> *ptrNumber = 10

==================change(int*& ptr)====================
    &ptr = 0x28ac3c
    ptr  = 0x800102c0
=======================================================

<<< *ptrNumber = 100

From the above output, we see

&ptrNumber = &ptr

So, ptr is alias of ptrNumber. You can modify ptrNumber inside function void change(int*& ptr) by modifying ptr. For example, you can point ptr to another memory location as below:

#include <iostream>
using namespace std;

void change(int*& ptr) {
    cout << endl;
    cout << "==================change(int*& ptr)====================" << endl;
    cout << "    &ptr = " << &ptr << endl;
    cout << "    >>> ptr = " << ptr << endl;
    ptr = new int(20);
    cout << "    <<< ptr = " << ptr << endl;
    cout << "=======================================================" << endl;
    cout << endl;
}

int main(void) {
    int* ptrNumber = new int(10);

    cout << endl;
    cout << ">>> &ptrNumber = " << &ptrNumber << endl;
    cout << ">>> ptrNumber = " << ptrNumber << endl;
    cout << ">>> *ptrNumber = " << *ptrNumber << endl;
    change(ptrNumber);
    cout << "<<< &ptrNumber = " << &ptrNumber << endl;
    cout << "<<< ptrNumber = " << ptrNumber << endl;
    cout << "<<< *ptrNumber = " << *ptrNumber << endl;
}

New output:

$ ./out_pointer.exe

>>> &ptrNumber = 0x28ac3c
>>> ptrNumber = 0x800102c0
>>> *ptrNumber = 10

==================change(int*& ptr)====================
    &ptr = 0x28ac3c
    >>> ptr = 0x800102c0
    <<< ptr = 0x80048328
=======================================================

<<< &ptrNumber = 0x28ac3c
<<< ptrNumber = 0x80048328
<<< *ptrNumber = 20
Son Nguyen
  • 195
  • 1
  • 10
0

The problem is, int*&val can only be passed an lvalue, which the result of &myVal is not. By changing the signature to void set(int* const& val), it's telling the compiler you're not going to change the value of the pointer.

However, you normally wouldn't do that, only because if you're not going to change the value of the pointer, then passing the pointer by value is the most straightforward way to pass the value. And if you are going to change the value of the pointer, then you need to create a temporary to receive the result.

Glen Selle
  • 3,966
  • 4
  • 37
  • 59
Dave S
  • 20,507
  • 3
  • 48
  • 68