C ++: является ли возвращаемое значение L-значением? - PullRequest
70 голосов
/ 24 мая 2011

Рассмотрим этот код:

struct foo
{
  int a;
};

foo q() { foo f; f.a =4; return f;}

int main()
{
  foo i;
  i.a = 5;
  q() = i;
}

Ни один компилятор не жалуется на это, даже Clang. Почему q() = ... строка правильная?

Ответы [ 3 ]

66 голосов
/ 24 мая 2011

Нет, возвращаемое значение функции является l-значением тогда и только тогда, когда оно является ссылкой (C ++ 03).(5.2.2 [expr.call] / 10)

Если возвращаемый тип является базовым типом, то это будет ошибкой компиляции.(5.17 [expr.ass] / 1)

Причина, по которой это работает, заключается в том, что вам разрешено вызывать функции-члены (даже не const функции-члены) для r-значений типа класса и назначенияиз foo является функцией-членом, определенной реализацией: foo& foo::operator=(const foo&).Ограничения для операторов в разделе 5 применяются только к встроенным операторам , (5 [expr] / 3), если разрешение перегрузки выбирает перегруженный вызов функции для оператора, тогда вместо этого применяются ограничения для этого вызова функции.

Именно поэтому иногда рекомендуется возвращать объекты типа класса в виде const объектов (например, const foo q();), однако это может оказать негативное влияние на C ++ 0x, где он может запретить семантику перемещения.работать как надо.

8 голосов
/ 24 мая 2011

Поскольку структуры могут быть назначены, а ваш q() возвращает копию struct foo, поэтому он присваивает возвращаемую структуру указанному значению.

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

Это имеет больше смысла (хотя все еще не является "лучшей практикой")

struct foo
{
  int a;
};

foo* q() { foo *f = new malloc(sizeof(foo)); f->a = 4; return f; }

int main()
{
  foo i;
  i.a = 5;

  //sets the contents of the newly created foo
  //to the contents of your i variable
  (*(q())) = i;
}
6 голосов
/ 25 мая 2011

Одно интересное применение этого:

void f(const std::string& x);
std::string g() { return "<tag>"; }

...

f(g() += "</tag>");

Здесь g() += изменяет временное хранилище, что может быть быстрее, чем создание дополнительного временного с +, поскольку куча, выделенная для возвращаемого значения g (), может уже иметь достаточную свободную емкость для размещения </tag>.

Смотрите, запустите на ideone.com с GCC / C ++ 11 .

Теперь, какой новичок сказал что-то про оптимизацию и зло ...? ; -.]

...