Есть ли случай, когда возврат ссылки RValue (& &) полезен?

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

MyClass&& func( ... );

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

70 голосов | спросил towi 24 PMpSun, 24 Apr 2011 15:30:34 +040030Sunday 2011, 15:30:34

5 ответов


0

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

template <class Iter>
class move_iterator
{
private:
    Iter i_;
public:
    ...
    value_type&& operator*() const {return std::move(*i_);}
    ...
};
ответил Howard Hinnant 24 PMpSun, 24 Apr 2011 17:54:59 +040054Sunday 2011, 17:54:59
0

Это следует за комментарием 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.

ответил Clinton 2 Mayam11 2011, 08:27:15
0

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

ответил Puppy 24 PMpSun, 24 Apr 2011 15:34:34 +040034Sunday 2011, 15:34:34
0

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

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

Type&& func();

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

Type&& ref_a = func();

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

const Type& ref_a = func();

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

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

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

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

ответил hangyuan 28 J000000Tuesday15 2015, 02:49:18
0

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

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

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

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 замена.

ответил CoffeeandCode 28 J000000Tuesday15 2015, 03:03:06

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132