0

Why this can't compile:

// RefToPointers.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>

using std::cout;

class T
{
public:
    T(int* value):data_(value)
    {
    }
    int* data_;
    int* getData_()
    {
        return data_;
    }
    int getValue()//<----------Here I do not return by ref
    {
        return *data_;
    }
};



  void fnc(const int*& left, const int*& right )//<------Doesn't work even though  
//it is identical to the example below just type is different. Why?
    {
        const int* tmp = left;
        left = right;
        right = tmp;
}

void fnc(const int& left,const int& right)//<---Here I pass by ref
{

}

int _tmain(int argc, _TCHAR* argv[])
{
    //int* one = new int(1);
    //int* two = new int(2);
    //cout << "Pointers before change:" << *one << '\t' << *two << '\n';
    //fnc(one,two);
    //cout << "Pointers before change:" << *one << '\t' << *two << '\n';

    T one(new int(1));


        T two(new int(2));
            fnc(one.getData_(),two.getData_());//<---This do not work
            fnc(one.getValue(),two.getValue());//<<------This still works even thoug I'm   
    //returning by value and fnc is taking args by ref. Why does it work with int
 //by not with int*?
            return 0;
    }

I'm getting following error:

_error C2664: 'fnc' : cannot convert parameter 1 from 'int *' to 'int *&_

And why on earth underscores do not make font italic in line where error is listed?

There is nothing we can do
  • 23,727
  • 30
  • 106
  • 194

5 Answers5

1
int* getData_()

This function returns an r-value, but an int*& expects an l-value, so the compiler will complain. You should return an int*& in getData_() also.

int*& getData_() { return data_; }

Meanwhile, a const int& can accept an rvalue, so the 2nd fnc compiles correctly. A const reference is not exactly the same as a (mutable) reference.

(Of course, it is better to provide a const version as well.

int* const& getData_() const { return data_; }
// or: int* getData_() const { return data_; }

Also note that your program will leak memory as you new stuff without delete-ing it.)

kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
  • @KennyTM thanks that works but also it did mess with my head little bit. I thought that one of many reasons of returning a pointer is a way of ensuring that no tmp copy is made. For example if I would have another fnc (look my edited question) I do not have to specify as a return type ref to int and it still works but it doesn't work when I'm returning a pointer, why? Would you be so kind and explain that to me? – There is nothing we can do Sep 23 '10 at 19:07
  • @There: Because that's a `const int&`, not an `int&`. A const-reference can accept rvalues. Also, you are swapping the pointer value themselves in `fnc`, not the content pointed by the pointer. Therefore, the type being a pointer doesn't change the situation. – kennytm Sep 23 '10 at 19:16
  • @KennyTM it doesn't work for pointers though (const ref to rvalue). I've changed return type of getData() to int* and params in fnc to const int*& and it doesn't work and it's identical to the example with int in which it works (const to rvalue). Why? – There is nothing we can do Sep 23 '10 at 19:24
  • @There: `const int*&` means a mutable reference to a const pointer of int. `const int*& = int const*&`. You need `int* const&` which means a const reference to a mutable pointer of int. – kennytm Sep 23 '10 at 19:34
  • @KennyTM It works now but... ahem... I can't agree with your way of reading things for I would read this const int*& as ref to pointer to int which is const and this int*const& as ref to const pointer to int not const ref to mutable pointer of int because this pointer is in fact const not mutable and refs are const by default. I hope you agree with me. – There is nothing we can do Sep 23 '10 at 19:38
  • @There: I can't agree with you because that's how C and C++ works. Although in `const int*&` the value pointed to is const, the pointer (address) itself is mutable. – kennytm Sep 23 '10 at 19:45
  • @KennyTM but in this example 'int*const&' pointer isn't mutable. It's const and you're saying that it is mutable. – There is nothing we can do Sep 23 '10 at 19:47
  • @There: No the address is const but the thing it pointed to is mutable. If you need everything to be const you need `const int* const&`. – kennytm Sep 23 '10 at 19:49
  • @KennyTM but you weren't saying that the thing pointed to is mutable. You were saying that pointer is mutable and it isn't the case. Your words " Although in const int*& the value pointed to is const, the pointer (address) itself is mutable" So if address is const the pointer itself is const isn't it? If you wanna check it try to move this pointer. And then you have to agree with me ;) – There is nothing we can do Sep 23 '10 at 19:53
  • @There: `int* const& p = ...;`, `p = NULL` is error, `*p = 1` is fine; `const int*& q = ...;`, `q = NULL` is fine, `*q = 1` is error. – kennytm Sep 23 '10 at 20:05
  • @KennyTM so as you've discovered for yourself that you've made mistake are you actually going to say that I was right? Because what you've showed in your last post only proves what I was saying that int*const& is a ref to const (not mutable as you were saying) pointer to int. Do you actually see that you are wrong? – There is nothing we can do Sep 24 '10 at 07:30
  • @KennyTM just to be clear what we talking about: int*const& : you are saying that this is const ref to mutable pointer to const int which is wrong and I'm saying that this is ref to const pointer to mutable int. Did you remove or edit one of your comments (the one in which you've described what int*const& means)? – There is nothing we can do Sep 24 '10 at 07:34
  • @KennyTM In one of your comments you're saying that: "const int*& means a mutable reference to a const pointer of int" Wrong. It means ref to pointer to const int. Refs by nature aren't mutable. – There is nothing we can do Sep 24 '10 at 07:35
  • @There: By "const/mutable pointer/reference" I have always been meaning the thing *it refers to* is const/mutable. Looks like we have miscommunication here. – kennytm Sep 24 '10 at 08:03
  • @KennyTM In that case I'm sorry to say that but you were just plain wrong because there is a difference (semantical difference) between const int* and int*const They do not mean the same thing. You have to start using correct forms of naming things, otherwise people will think that you do not fully understand what you're talking about. I hope you agree with me that in our profession precise is the path we should follow not the vague path. – There is nothing we can do Sep 24 '10 at 08:16
1

getData() returns an rvalue. You can't take a reference to an rvalue pointer.

You have two choices:

1) Pass fnc() lvalues:

int* lhs = one.getData_();
int* rhs = two.getData_();
fnc(lhs, rhs);

2) Or, since you are passing pointer references, which really are the same size as pointers themselves, why not just pass pointers?

void fnc(int* left, int* right )
{
    int* tmp = left;
    left = right;
    right = tmp;
}

EDIT:

A little bit more on lvalues and rvalues. "lvalue" used to mean "an expression that can be on the left of an = operation." rvalue was effectively the converse: an rvalue was any expression that could not be on the left of an = operation.

Things are a little bit more complex than that now, but that's still a pretty good way to understand lvalues and rvalues.

Now, consider the following code:

int val()
{
    return 42;
}

int main()
{
    int* p = &val();
}

val() returns an int by value -- in other words, it returns an unnamed temporary value. Should you be able to take the address of that temporary?

You might think, "well, yeah, why not?" But the answer is actually no, you can't take the address of the temporary. The reason has to do with the lifetime of that temporary. It's scope is limited to the expression in which it was created. In other words: val(). As soon as val() has been completely evaluated, the temporary ceases to exist. In effect, it falls off the stack. By the time int* p = & is evaluated, the temporary is long gone. There's nothing left to take the address of.

This is basically why you can't take the address of an rvalue, which by extension is why you can't get a reference to an rvalue's address.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • John, the 2) part is doing nothing. It is exchanging local copies of pointers to `fnc` that are forgot about when `fnc` ends. – Diego Sevilla Sep 23 '10 at 19:12
  • Thank you for your answer. First I answer to your question: I'm not passing pointers because I want those pointers to point to the values they are made to point inside the fnc body. If I wouldn't pass it by ref this whole operation wouldn't have any effect. Now when I've answered to your question here is mine: Where is the difference between fnc(one.getData(),...) and what you've shown? Is it that in what you've shown there are variables created on stack and that's why they are lvalues? It doesn't make sense to me and you probably agree with me – There is nothing we can do Sep 23 '10 at 19:18
  • continue that in order to send int (just int) to a function you first create variable int left = getValue(); and then you pass it (the left variable) to function fnc(int a)? What you've normally would do is this fnc(getValue()) without creating this unnecessary variable? Isn't that so? I'll be really glad if you could explain that to me. – There is nothing we can do Sep 23 '10 at 19:18
  • @There: I've posted an edit to my post which I hope explains the whole lvalue/rvalue thing a little more clearly. – John Dibling Sep 23 '10 at 19:49
  • @Downvoter: If there is an error in my post, please let me know so I can correct it. This topic is actually somewhat complex. – John Dibling Sep 23 '10 at 20:49
0

You can take references (&) only on variables, not on return values from functions, when you change it, where will the change go?

nothrow
  • 15,882
  • 9
  • 57
  • 104
0

Because getData_() returns int* and not int*&. This means that you pass temporaries as actual parameters to fnc and temporaries cannot be converted to (mutable) references. Change getData_() to return int*&.

Tomek
  • 4,554
  • 1
  • 19
  • 19
0

Note that getData_() returns the pointer by value. This means that a temporary is used to hold the returned pointer from the call. You cannot create (non-constant) references to temporaries (what sense would it have if you would be exchanging two temporary copies of the internal pointer in the T class?)

(As for your second question, I think the italic is cancelled when other format modifiers (such as *) appear in your line...)

Diego Sevilla
  • 28,636
  • 4
  • 59
  • 87