Рассмотрим этот код:
struct foo
{
int a;
};
foo q() { foo f; f.a =4; return f;}
int main()
{
foo i;
i.a = 5;
q() = i;
}
Никакой компилятор не жалуется на это, даже Clang. Почему строка q() = ...
верна?
Рассмотрим этот код:
struct foo
{
int a;
};
foo q() { foo f; f.a =4; return f;}
int main()
{
foo i;
i.a = 5;
q() = i;
}
Никакой компилятор не жалуется на это, даже Clang. Почему строка q() = ...
верна?
Нет, возвращаемое значение функции является l-значением тогда и только тогда, когда оно является ссылкой (С++ 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();
), однако это может иметь негативное влияние на С++ 0x, где оно может препятствовать работе семантики перемещения, поскольку они следует.
Так как structs можно назначить, а ваш 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;
}
Одно интересное приложение:
void f(const std::string& x);
std::string g() { return "<tag>"; }
...
f(g() += "</tag>");
Здесь g() +=
изменяет временную, которая может быть быстрее, создавая дополнительное временное событие с +
, потому что куча, выделенная для возвращаемого значения g(), может уже иметь достаточную запасную емкость для размещения </tag>
.
Посмотрите, как он запускает на ideone.com с помощью GCC/С++ 11.
Теперь, какой компьютерный новичок сказал что-то о оптимизациях и зле...?; -.]