#c
#c
Вопрос:
Каким правилам или советам я должен следовать, чтобы позволить функции использовать оптимизацию NRV (именованное возвращаемое значение) в функции? Я усвоил эти советы из разных мест, но не знаю, правильно ли это, насколько я понимаю:
- возвращаемый объект не должен иметь никакого имени внутри функции (тогда почему он называется оптимизацией возвращаемого значения !!)
- оператор return должен содержать объект, заключенный в круглые скобки
- возвращаемый объект должен иметь явный и встроенный конструктор копирования
Комментарии:
1. Я ответил вам о 1 (который, кажется, является основным моментом), но я действительно не понял 2, и я не уверен насчет 3, но я не думаю, что компилятор заботится о том, чтобы конструктор копирования был встроенным и определялся явно (хотя, вероятно, у него не должно быть ключевое слово explicit, поскольку его нужно было бы вызывать неявно, если оптимизация не происходит).
Ответ №1:
Если вы имеете в виду NRVO (оптимизацию именованного возвращаемого значения) в отличие от RVO (оптимизацию возвращаемого значения), то объект должен быть назван внутри функции. В противном случае она имела бы право только на RVO, а не на NRVO. Таким образом, есть довольно веская причина для того, чтобы называть это оптимизацией с именем возвращаемого значения.
Ознакомьтесь со следующими примерами:
RVO:
BigObject foo(int x, int y)
{
// Returned BigObject is created ad-hoc, and has no local 'name'.
return BigObject(x, y);
}
void bar()
{
BigObject obj = foo(4, 6);
}
Оптимизирующий компилятор будет преобразован в этот псевдокод:
void foo(int x, int y, BigObjectamp; ret)
{
ret._constructor_(x, y);
}
void bar()
{
BigObject obj; // Allocate obj on the stack, but don't construct it just yet!
foo(4, 6, obj); // Now obj is constructed by foo()
}
NRVO:
BigObject foo(int x, int y, int z)
{
// Returned BigObject has a local 'name' in foo(), which is obj.
BigObject obj(x, y);
// Do something with obj
obj.setZ(z);
return obj;
}
void bar()
{
BigObject obj = foo(4, 6, 7);
}
Оптимизирующий компилятор будет преобразован в этот псевдокод:
void foo(int x, int y, int z, BigObjectamp; ret)
{
ret._constructor_(x, y);
// Do something with ret
ret.setZ(z);
}
void bar()
{
BigObject obj; // Allocate obj on the stack, but don't construct it just yet!
foo(4, 6, 7, obj); // Now obj is constructed by foo()
}
Обратите внимание, что то, произойдет ли оптимизация на самом деле, во многом зависит от компилятора. Некоторые компиляторы (например, очень старые компиляторы) вообще не будут выполнять RVO или NRVO, в то время как другие компиляторы могут иметь другие ограничения на эту оптимизацию. Вот описание ограничений, которые MSVC накладывает на NRVO:
http://msdn.microsoft.com/en-us/library/ms364057 (v = против80).aspx#nrvo_cpp05_topic3
Комментарии:
1. аааа! я ошибочно думал, что RVO — это сокращенная форма NRVO
2. Нет. Оба выполняются компилятором, и пользователь вообще не может ими управлять. NRVO выполняется, когда объект имеет «локальное имя» в возвращающей функции, а RVO выполняется, когда он создается в той же строке, что и
return
оператор.