tags:

views:

110

answers:

5

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?

+1  A: 
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
@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
KennyTM
There is nothing we can do
KennyTM
There is nothing we can do
KennyTM
There is nothing we can do
KennyTM
@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*)
There is nothing we can do
@There: `int* const`, `p = NULL` is error, `*p = 1` is fine; `const int*`, `q = NULL` is fine, `*q = 1` is error.
KennyTM
There is nothing we can do
There is nothing we can do
There is nothing we can do
@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
@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
A: 

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

Yossarian
A: 

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
A: 

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
+1  A: 

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
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
@John 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
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
@There: I've posted an edit to my post which I hope explains the whole lvalue/rvalue thing a little more clearly.
John Dibling
@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