Возвращаемые значения в c ++ 03 против 11

Я провел несколько часов о Rvalue s и lvalue. Вот что я понимаю

int main()
{
//.....
Foo foo = Bar1();
foo = Bar2();
//......
}

Foo Bar1()
{
//Do something including create foo
return foo;
}

Foo& Bar2()
{
//Do something including create foo
return foo;
}

Под с ++ 03, Bar1() скопирует возвращаемый объект (непосредственно перед возвратом), а затем вернет адрес скопированного объекта; выполнение расточительной копии объекта, который собирается быть уничтоженным. Bar2() вернет объект, созданный в функции.

Под с ++ 11, Bar1() а также Bar2() будет по существу эквивалентным (а также эквивалентным Bar2() с ++ 03).

Это правильно? Если нет, пожалуйста, уточните.

0

Решение

Понятие rvalues ​​и lvalues ​​не изменилось с более старых C ++ на C ++ 11. То, что вы описываете как «C ++ 03», это то, что должно произойти. Некоторые оптимизации компилятора в некоторых случаях могут уменьшить количество ненужных копий (включая ненужные вызовы конструктора копирования!), Но в остальном это то же самое.

Что изменилось, так это то, что в C ++ 11 появилась концепция rvalue-reference (T&&).

На нем есть несколько статей, которые вы можете найти в Google, например здесь:

http://thbecker.net/articles/rvalue_references/section_01.html

1

Другие решения

Они не то же самое. Bar2() это UB по обоим стандартам. Вы не можете вернуть объект, созданный в стеке, по ссылке.

В С ++ 03 Bar1() может воспользоваться RVO и ничего не будет скопировано. В С ++ 11 Bar1() будет даже использовать RVO или будет использовать конструктор перемещения, если RVO невозможен.

6

Bar2() не создает копии ни в C ++ 2003, ни в C ++ 2011. Для Bar1() копия foo создается как в C ++ 2003, так и в C ++ 2011. Использование ссылок на rvalue применяется только в том случае, если у вас действительно есть значение rvalue или если у вас есть значение lvalue, которое собирается исчезнуть и оно возвращается.

Конечно, случаем является неопределенное поведение, потому что foo возвращение является foo инициализируется. То есть, кажется, ваш пример испорчен, не указав, что foo подразумевается, когда он возвращается. Предполагая, что каждая функция имеет локальную переменную foo, Bar2() неопределенное поведение в соответствии с обоими стандартами и Bar1() несколько отличается:

  • Если есть конструктор перемещения для Foo, C ++ 2011 может использовать конструктор перемещения, в то время как C ++ 2003 может использовать конструктор копирования.
  • Используется ли конструктор перемещения или конструктор копирования, зависит от остальной части функции и компилятора: если все return заявления в Bar1() вернуть fooСтроительство дополнительного объекта будет выполняться большинством компиляторов.
1

Bar2 () вернет объект, созданный в функции.

Это явно неправильно. Bar2() вернется ссылка к какому-то объекту. (Примечание: это будет UB, если объект создается в стеке внутри Bar2()).

В соответствии с c ++ 11 Bar1 () и Bar2 () по существу будут эквивалентны (а также эквивалентны Bar2 () из c ++ 03).

Под C ++ 11 смысл был бы таким же. Что вас действительно интересует, так это семантика перемещения:

Foo Bar3()
{
//Do something
return std::move(foo);
}

Это не будет выполнять конструктор копирования, а конструктор перемещения — который должен быть гораздо менее требовательным к ресурсам.

0

Эта статья может быть интересна для вас: Хотите скорость? Передать по значению.

В C ++ 03 Bar1() может скопировать объект (но это оптимизировано с так называемым разрешением копирования — см. ссылку).

В C ++ 11 по сути ничего не изменилось. Компилятору разрешено либо вызывать FooКопировать конструктор или FooДвигайся конструктор или сделай копию elision. Но поскольку даже в C ++ 03 копия будет удалена, Bar1() делает то же самое в C ++ 11 и C ++ 03.

Bar2() верните просто ссылку, в C ++ 11 нет ничего другого. Возвращение ссылок может быть критичным. Если foo будет локальным значением, ссылка на уже уничтоженную переменную возвращается, но не на это.

0
По вопросам рекламы [email protected]