Есть ли случай, когда возврат ссылки RValue (&&) полезен? - PullRequest
72 голосов
/ 24 апреля 2011

Есть ли причина, по которой функция должна возвращать ссылку RValue ? Техника или трюк, или идиома или шаблон?

MyClass&& func( ... );

Мне известно об опасности возврата ссылок в целом, но иногда мы все равно делаем это, не так ли (T& T::operator=(T) - это всего лишь один идиоматический пример). Но как насчет T&& func(...)? Есть ли какое-нибудь общее место, где мы бы выиграли от этого? Возможно, отличается, когда кто-то пишет библиотеку или код API, по сравнению с просто клиентским кодом?

Ответы [ 5 ]

56 голосов
/ 24 апреля 2011

Есть несколько случаев, когда это уместно, но они относительно редки. Случай встречается в одном примере, когда вы хотите разрешить клиенту переходить от элемента данных. Например:

template <class Iter>
class move_iterator
{
private:
    Iter i_;
public:
    ...
    value_type&& operator*() const {return std::move(*i_);}
    ...
};
17 голосов
/ 02 мая 2011

Это следует за комментарием Towi.Вы никогда не хотите возвращать ссылки на локальные переменные.Но у вас может быть это:

vector<N> operator+(const vector<N>& x1, const vector<N>& x2) { vector<N> x3 = x1; x3 += x2; return x3; }
vector<N>&& operator+(const vector<N>& x1, vector<N>&& x2)    { x2 += x1; return std::move(x2); }
vector<N>&& operator+(vector<N>&& x1, const vector<N>& x2)    { x1 += x2; return std::move(x1); }
vector<N>&& operator+(vector<N>&& x1, vector<N>&& x2)         { x1 += x2; return std::move(x1); }

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

7 голосов
/ 24 апреля 2011

Нет. Просто верните значение. Возврат ссылок вообще не опасен - он возвращает ссылки на локальные переменные, что опасно. Однако возврат ссылки на rvalue практически бесполезен почти во всех ситуациях (я думаю, если вы написали std::move или что-то в этом роде).

0 голосов
/ 28 июля 2015

Еще один возможный случай: когда вам нужно распаковать кортеж и передать значения функции.

Это может быть полезно в этом случае, если вы не уверены в copy-elision.

Такой пример:

template<typename ... Args>
class store_args{
    public:
        std::tuple<Args...> args;

        template<typename Functor, size_t ... Indices>
        decltype(auto) apply_helper(Functor &&f, std::integer_sequence<size_t, Indices...>&&){
            return std::move(f(std::forward<Args>(std::get<Indices>(args))...));
        }

        template<typename Functor>
        auto apply(Functor &&f){
            return apply_helper(std::move(f), std::make_index_sequence<sizeof...(Args)>{});
        }
};

довольно редкий случай, если вы не пишете какую-либо форму замены std::bind или std::thread.

0 голосов
/ 28 июля 2015

Вы можете вернуться по ссылке, если уверены, что указанный объект не выйдет из области видимости после выхода из функции, например, это ссылка на глобальный объект или функция-член, возвращающая ссылку на поля класса и т. Д.

Это возвращаемое правило ссылки одинаково как для lvalue, так и для rvalue.Разница в том, как вы хотите использовать возвращенную ссылку.Как я вижу, возвращение по rvalue-ссылке встречается редко.Если у вас есть функция:

Type&& func();

Вам не понравится такой код:

Type&& ref_a = func();

, потому что он эффективно определяет ref_a как Type &, так как именованная ссылка rvalue является lvalue, и никакого фактического перемещениябудет выполнено здесь.Это похоже на:

const Type& ref_a = func();

за исключением того, что фактический ref_a является неконстантной ссылкой на lvalue.

И это также не очень полезно, даже если вы напрямую передаете func () другой функции, которая принимает аргумент Type &&, потому что это все еще именованная ссылка внутри этой функции.

void anotherFunc(Type&& t) {
  // t is a named reference
}
anotherFunc(func());

Отношение func() и anotherFunc () больше похожи на «авторизацию», согласно которой func () соглашается, что anotherFunc () может стать владельцем (или вы можете сказать «украсть») возвращаемого объекта из func ().Но это соглашение очень слабое.Неконстантная ссылка lvalue все еще может быть «украдена» вызывающими.На самом деле функции редко определяются, чтобы принимать rvalue ссылочные аргументы.Наиболее распространенным случаем является то, что «anotherFunc» является именем класса, а anotherFunc () фактически является конструктором перемещения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...