Правильно названные временные и rvalue-ссылки / ход - PullRequest
4 голосов
/ 04 октября 2011

До C ++ 11 и в качестве стандартной идиомы программирования временные значения часто назначаются переменным, чтобы сделать код чище. Для небольших типов обычно делается копия, а для больших типов может быть ссылка, например:

int a = int_func();
T const & obj = obj_func();
some_func( a, obj );

Теперь сравните это со встроенной формой:

some_func( int_func(), obj_func() );

До C ++ 11 это имело почти идентичное семантическое значение. С введением семантики rvalue-reference и move вышеперечисленное полностью изменилось. В частности, вынудив obj к типу T const &, вы удалили возможность использовать конструктор перемещения, тогда как для встроенной формы тип может быть T&&.

Учитывая, что первая является общей парадигмой, есть ли в стандарте что-нибудь, что позволило бы оптимизатору использовать конструктор перемещения в первом случае? То есть может ли компилятор игнорировать привязку к T const & и вместо этого трактовать его как T&&, или, как я подозреваю, это нарушит правила абстрактной машины?

Вторая часть вопроса, чтобы сделать это правильно в C ++ 11 (без устранения именованных временных), нам нужно как-то объявить правильную ссылку-значение. Мы также можем использовать ключевое слово auto. Итак, как же правильный способ сделать это? Мое предположение:

auto&& obj = obj_func();

Ответы [ 3 ]

7 голосов
/ 04 октября 2011

Часть 1:

Компилятору не разрешено неявно преобразовывать obj в неконстантное значение и, таким образом, использовать конструктор перемещения при вызове some_func.

Часть 2:

auto&& obj = obj_func();

Это создаст неконстантную ссылку на временную, но не будет неявно перемещаться из при вызове some_func, потому что obj является lvalue . Чтобы преобразовать его в значение, вы должны использовать std::move на сайте вызова:

some_func( a, std::move(obj) );
4 голосов
/ 04 октября 2011

Я сомневаюсь, что это можно оптимизировать, так как не ясно, будете ли вы снова использовать временный или нет:

Foo x = get_foo(); // using best-possible constructor and (N)RVO anyway
do_something(x);
do_something_else(x);
//...

Если вы действительно заинтересованы в использовании семантики перемещения где-то (но сначала обязательно зайдите в профиль, чтобы убедиться, что это действительно важно), вы можете сделать это явно с помощью move:

Foo y = get_foo();
do_oneoff_thing(std::move(y));  // now y is no longer valid!

Я бы сказал, что если что-то подходит для перемещения, то вы могли бы сделать встраивание самостоятельно и обойтись без дополнительной локальной переменной. В конце концов, что хорошего в такой временной переменной, если она используется только один раз? Единственный сценарий, который приходит на ум, - это если last использование локальной переменной может использовать семантику перемещения, так что вы можете добавить std::move к окончательному виду. Это звучит как угроза технического обслуживания, и вам действительно нужна веская причина, чтобы написать это.

3 голосов
/ 04 октября 2011

Я не думаю, что привязка const & к временному с целью продления срока службы настолько распространена.На самом деле, в C ++ 03 во многих случаях можно удалить копию, просто передав значение и вызывая функцию в том, что вы называете встроенной формой : some_func( int_func(), obj_func() ), так чтопроблема, которую вы заметили в C ++ 11, возникла бы в C ++ 03 (немного по-другому)

Что касается привязки константной ссылки, в случае, если obj_func() возвращает объект типа T, приведенный выше код является просто громоздким способом выполнения T obj = obj_func();, который не предлагает никаких преимуществ, кроме как заставить людей задаться вопросом , почему был необходим.

Если obj_func() возвращает тип T1, полученный из T, этот трюк позволяет вам игнорировать точный тип возвращаемого значения, но этого также можно достичь с помощью ключевого слова auto, так что в любом случае у вас есть локальная переменная obj.

Правильный способ передачи obj в функцию - если вы закончили с ней, и функция может переместить значение из obj во внутренний объект, будетбыть на самом деле двигаться :

some_func( a, std::move(obj) );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...