Проблема со ссылками на указатели - PullRequest
0 голосов
/ 23 сентября 2010

Почему это не скомпилируется:

// 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;
    }

Я получаю следующую ошибку:

_error C2664: 'fnc': невозможно преобразовать параметр 1 из 'int *' в 'int * & _

И почему на земле подчеркивания не делают курсив шрифтом в строке, где указана ошибка?

Ответы [ 5 ]

1 голос
/ 23 сентября 2010

getData() возвращает значение. Вы не можете взять ссылку на указатель rvalue.

У вас есть два варианта:

1) Pass fnc() lvalues:

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

2) Или, поскольку вы передаете ссылки на указатели, которые на самом деле имеют тот же размер, что и сами указатели, почему бы просто не передать указатели?

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

EDIT:

Еще немного о lvalues ​​и rvalues. «lvalue» используется для обозначения «выражения, которое может находиться слева от операции =». Фактически, rvalue было обратным: rvalue было любым выражением, которое не могло быть слева от операции =.

Сейчас все немного сложнее, но это все же довольно хороший способ понять lvalues ​​и rvalues.

Теперь рассмотрим следующий код:

int val()
{
    return 42;
}

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

val() возвращает int по значению - другими словами, он возвращает неназванное временное значение. Должны ли вы быть в состоянии взять адрес этого временного?

Вы можете подумать: "Ну, да, а почему бы и нет?" Но ответ на самом деле нет, вы не можете взять адрес временного. Причина в том, что время жизни этого временного. Его область действия ограничена выражением, в котором он был создан. Другими словами: val(). Как только val() был полностью оценен, временное прекращение существования. По сути, он падает со стека. К моменту оценки int* p = & временное значение давно исчезло. Там ничего не осталось взять адрес.

Это в основном то, почему вы не можете получить адрес rvalue, поэтому, по расширению, вы не можете получить ссылку на адрес rvalue.

1 голос
/ 23 сентября 2010
int* getData_()

Эта функция возвращает значение r, но int*& ожидает значение l, поэтому компилятор будет жаловаться. Вы также должны вернуть int*& в getData_().

int*& getData_() { return data_; }

Между тем, const int& может принимать значение r, поэтому 2-й fnc компилируется правильно. Ссылка const равна , а не точно так же, как (изменяемая) ссылка.

(Конечно, лучше также предоставить константную версию.

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

Также обратите внимание, что ваша программа будет пропускать память, если вы набираете new содержимого без delete -инго.)

0 голосов
/ 23 сентября 2010

Обратите внимание, что getData_() возвращает указатель по значению .Это означает, что временная переменная используется для хранения возвращенного указателя из вызова.Вы не можете создавать (непостоянные) ссылки на временные ссылки (какой смысл это иметь, если вы будете обменивать две временные копии внутреннего указателя в классе T?)

(Что касается вашего второго вопроса,Я думаю, курсив отменяется, когда в вашей строке появляются другие модификаторы формата (например, *) ...)

0 голосов
/ 23 сентября 2010

Потому что getData_ () возвращает int *, а не int * &. Это означает, что вы передаете временные значения как фактические параметры в fnc, и временные значения не могут быть преобразованы в (изменяемые) ссылки. Измените getData_ (), чтобы он возвращал int * &.

0 голосов
/ 23 сентября 2010

Вы можете брать ссылки (&) только на переменные, а не на возвращаемые значения из функций, когда вы их измените, куда эти изменения пойдут?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...