Почему это вызывает C2102: '& ' требует l-значения

мне было интересно, почему следующий код (уже закомментированы) вызовет
C2102: '&' requires l-value

есть ли лучший способ, чтобы избежать использования tmp переменной?

class a {
private:
    int *dummy;
public:
    int* get_dummy() const {
        return dummy;
    }
};

int main()
{
    a aa;

    // error C2102: '&' requires l-value
    //int** me = &(aa.get_dummy());

    // OK!
    int *tmp = aa.get_dummy();
    int** me = &(tmp);
}

5 ответов


, потому что a::get_dummy() возвращает безымянный временный объект (указатель int).
Объект, возвращаемый функцией сидеть на вершине кадра стека и бессмысленно получать его адрес, так как это может быть недопустимо после окончания выражения.


вместо этого вы можете определить:

int **get_dummy() ... return &dummy;

вы можете думать о R-значении как о выражении, по существу, тогда как l-значение является фактическим объектом. У выражений нет адресов, и даже если бы они были, трудно представить, какой хороший адрес был бы. Легко понять, как адрес объекта может быть полезным.

немного сложно понять такую проблему абстрактно. Самый лучший способ развить понимание указателей и скомпилированных языков это изучение языка ассемблера.


нет.

какой адрес будет me содержать иное? Вот вы дали ему адрес tmp -- но если вы замените его с int** me = &aa.get_dummy();, куда она указывала?

на этот вопрос нет значимого ответа, поэтому стандарт требует, чтобы аргумент & будьте lvalue.


на & оператор должен быть применен к lvalue. Когда вызов aa.get_dummy() не присваивается переменной, ее возвращаемое значение помещается только в стек, поэтому было бы глупо (и ошибочно) получить адрес элемента стека.


компилятор прав, согласно ISO C++ 5.3.1.3§:

результатом унарного оператора & является указатель на его операнд. Этот операнд должен быть lvalue или квалифицированным id.

другими словами, вы можете взять адрес всего, что имя.

значения, возвращаемые из функции по стоимости не имеют имени и часто возвращаются через зарегистрироваться. Так что нет никакого"адрес " говорить о том, как значение не находится в памяти!

можно утверждать, что компилятор может быть умнее, обнаружить это и сохранить значение в стеке на время выражения, в котором используется адрес. Но это подвержено ошибкам (вы можете "утечь" указатель за пределы выражения) и, очевидно, будет расширение стандарта (т. е. не гарантируется совместимость). Так индекса MSVC просто запрещает.

увлекательно, компилятор is что умный когда дело доходит до ссылка к rvalue. Но нет такой функции указатель к rvalue.

чтобы ответить на ваш вопрос: попробуйте свести к минимуму взятие адресов вещей; взятие адреса переменной предотвращает оптимизатор от ввода его в регистр. Но если вам нужно, верните ссылку вместо этого:

class a {
private:
    int dummy;
public:
    int get_dummy() const {
        return dummy;
    }
    int& get_dummy() {
        return dummy;
    }
};

int main()
{
    a aa;

    int* me = &(aa.get_dummy());
}

обратите внимание, что имея const get_dummy() строго не требуется, но поможет оптимизатору в контекстах rvalue.