12

転送参照を使用する場合、同じ値を複数の関数に転送するのは悪い考えですか? 次のコードを検討してください。

template<typename Container>
constexpr auto
front(Container&& c)
-> typename Container::value_type
{ return std::forward<Container>(c).front(); }

template<typename Container>
constexpr auto
back(Container&& c)
-> typename Container::value_type
{ return std::forward<Container>(c).back(); }

template<typename Container>
constexpr auto
get_corner(Container&& c)
{
    return do_something(front(std::forward<Container(c)),
                        back(std::forward<Container>(c));
}

が左辺値参照の場合Container、関数は正常に機能します。ただし、移動が発生すると値が無効になるため、右辺値が渡される状況が心配です。私の疑問は次のとおりです。その場合、値カテゴリを失うことなくコンテナを転送する正しい方法はありますか?

4

4 に答える 4

4

実際には、右辺値参照バージョンはありませんstd::begin-(脇に置いconstexprて値を返す)だけがあります:

template <class C>
??? begin(C& );

template <class C>
??? begin(C const& );

左辺値コンテナーの場合は を取得iteratorし、右辺値コンテナーの場合は get const_iterator(または、コンテナー固有の同等のものが最終的に何であれ) を取得します。

あなたのコードの 1 つの本当の問題は、 を返すことdecltype(auto)です。左辺値コンテナーの場合は問題ありません。有効期間が関数を超えるオブジェクトへの参照を返します。しかし、右辺値コンテナーの場合、ダングリング参照が返されます。左辺値コンテナーの参照と右辺値コンテナーのを返す必要があります。

その上、コンテナを/にforward-ing することは、おそらくやりたいことではありません。の結果を移動反復子として条件付きでラップする方が効率的です。私のこの答えのようなもの:begin()end()select()

template <typename Container,
          typename V = decltype(*std::begin(std::declval<Container&>())),
          typename R = std::conditional_t<
              std::is_lvalue_reference<Container>::value,
              V,
              std::remove_reference_t<V>
              >
          >
constexpr R operator()(Container&& c)
{
    auto it = select(std::begin(c), std::end(c));
    return *make_forward_iterator<Container>(it);
}

そのすべてを表現するには、おそらくもっと冗長な方法があります。

于 2016-09-04T22:50:46.457 に答える
2

一般的に、はい、これは潜在的に危険です。

パラメーターを転送すると、ユニバーサル参照パラメーターによって受信された値が何らかの右辺値である場合、転送時に右辺値であり続けることが保証されます。値から移動することによって値を消費する関数 (move-constructor など) に値が最終的に転送される場合、その内部状態は後続の呼び出しで使用するために有効ではない可能性があります。

パラメータを転送しない場合、(一般に) 移動操作の対象にならないため、そのような動作から安全になります。

あなたの場合、frontand back(フリー関数とメンバー関数の両方) はコンテナーに対して移動を実行しないため、指定した特定の例は安全なはずです。ただし、これはコンテナを転送する理由がないことも示しています。右辺値は左辺値とは異なる扱いを受けないためです。これが、最初に値を転送することによって区別を維持する唯一の理由です。

于 2016-09-05T00:23:51.180 に答える