1

GCC 4.8.1 および Clang 2.9 以降がそれらをサポートするようになったため、参照修飾子 ( 「 *this の右辺値参照」とも呼ばれます) がより広く利用できるようになりました。たとえば、右辺値への代入を禁止することにより、クラスが組み込み型のように振る舞うことができます (そうしないと、右辺値から左辺値への不要なキャストが発生する可能性があります)。

class A
{
    // ...

public:
    A& operator=(A const& o) &
    {
        // ...
        return *this;
    }
};

一般に、右辺値のメンバー関数を呼び出すことは賢明constであるため、左辺値参照修飾子は適切ではありません (コピーを返す代わりにメンバーをクラスから移動するなどの最適化に右辺値修飾子を使用できる場合を除きます)。 )。

反対に、pre decrement/increment 演算子などの変更演算子は、通常、オブジェクトへの左辺値参照を返すため、左辺値修飾する必要があります。したがって、質問もあります: const-correctness(内部キャッシュを使用する場合の適切な適用を含む)のためにのみマークされていないconst概念的なメソッドとは別に、右辺値参照で変更/非メソッド(演算子を含む)を呼び出すことを許可する理由はありますか、これには現在、特定のスレッドセーフ保証の保証が含まれる可能性があります)は、コードベースで無視されていましたか?constconstmutable

明確にするために、言語レベルで右辺値の変更メソッドを禁止することを提案しているわけではありません (少なくともこれはレガシー コードを壊す可能性があります)。よりクリーンで安全な API につながります。ただし、そうしないと、よりクリーンで驚くべきAPI が得られない例に興味があります。

4

4 に答える 4

3

R 値で動作するミューテーターは、R​​ 値を使用して何らかのタスクを実行する場合に役立ちますが、その間は何らかの状態を維持します。例えば:

struct StringFormatter {
     StringFormatter &addString(string const &) &;
     StringFormatter &&addString(string const &) &&;
     StringFormatter &addNumber(int) &;
     StringFormatter &&addNumber(int) &&;
     string finish() &;
     string finish() &&;
};
int main() {
    string message = StringFormatter()
            .addString("The answer is: ")
            .addNumber(42)
            .finish();
    cout << message << endl;
}

L 値または R 値のいずれかを許可することで、オブジェクトを構築し、それをいくつかのミューテーターに渡し、式の結果を使用して、L 値に格納することなくタスクを実行できます。ミューテーターはメンバー関数です。

また、すべての変更演算子が自己への参照を返すわけではないことに注意してください。ユーザー定義のミューテーターは、必要な、または必要な署名を実装できます。ミューテーターは、オブジェクトの状態を消費して、より有用なものを返すことができます。R 値に作用することにより、オブジェクトが消費されるという事実は問題ではありません。そうでなければ、状態は破棄されていたからです。実際、オブジェクトの状態を消費して別の有用なものを生成するメンバー関数は、左辺値がいつ消費されるかを簡単に確認できるように、そのようにマークする必要があります。例えば:

MagicBuilder mbuilder("foo", "bar");

// Shouldn't compile (because it silently consumes mbuilder's state):
// MagicThing thing = mbuilder.construct();

// Good (the consumption of mbuilder is explicit):
MagicThing thing = move(mbuilder).construct();
于 2013-06-06T22:26:39.040 に答える
0

FWIW HIC++ は、代入演算子に関する限り、あなたに同意します:

http://www.codingstandard.com/rule/12-5-7-declare-assignment-operators-with-the-ref-qualifier/


非 const メソッドを右辺値に適用する必要がありますか?

この質問は私を困惑させます。私にとってより賢明な質問は次のとおりです。

const メソッドは、右辺値のみに適用する必要がありますか?

答えはノーだと思います。*thisconst rvalue 引数でオーバーロードしたい状況を想像できないのと同じように、const rvalue でオーバーロードしたい状況を想像できません。

右辺値をオーバーロードするのは、オブジェクトの内臓を盗むことができることを知っていれば、より効率的に処理できるためです。ただし、constオブジェクトの内臓を盗むことはできません。

をオーバーロードするには、次の 4 つの方法があります*this

struct foo {
    void bar() &;
    void bar() &&;
    void bar() const &;
    void bar() const &&;
};

後者の 2 つのオーバーロードの constness は、どちらも mutate できないことを意味するため、オーバーロードが許可されていることと、オーバーロードが許可されて*thisいることの間に違いはありません。オーバーロードがない場合、とにかく左辺値と右辺値の両方にバインドされます。const &*thisconst &&*thisconst &&const &

on のオーバーロードは役に立たず、実際には完全を期すためにのみ提供されていることを考えるとconst &&(間違っていることを証明してください!)、ref-qualifiers の残りの使用例は 1 つだけです: non-const rvalue のオーバーロード*thisです。&&オーバーロードの関数本体を定義することも、定義することもできます= delete(これは、オーバーロードのみが提供されている場合に暗黙的&に行われます)。&&関数本体の定義が役立つケースはたくさんあると想像できます。

のように、オーバーロードoperator->と unaryによってポインター セマンティクスを実装するプロキシ オブジェクトでは、その で ref-qualifiers を使用すると便利な場合があります。operator*boost::detail::operator_arrow_dispatchoperator*

template <typename T>
struct proxy {
    proxy(T obj) : m_obj(std::move(obj)) {}
    T const* operator->() const { return &m_obj; }
    T operator*() const& { return m_obj; }
    T operator*() && { return std::move(m_obj); }
private:
    T m_obj;
};

*thisが右辺値の場合operator*、コピーではなく移動によって返すことができます。

于 2014-06-29T17:58:09.703 に答える
0

値を取得する唯一の方法が別の値を変更することである場合に発生すると思います。たとえば、反復子は「+1」または「次へ」のメソッドを提供しません。したがって、stl リスト反復子のラッパーを作成しているとします (おそらく、独自のリストに基づくデータ構造の反復子を作成するため)。

class my_iter{
private:
    std::list::iterator<T> iter;
    void assign_to_next(std::list::iterator<T>&& rhs) {
        iter = std::move(++rhs);
    }
};

ここで、assign_to_next メソッドは反復子を取り、この反復子を割り当てて、その反復子の次の位置に配置します。これが役立つ状況を想像するのはそれほど難しくありませんが、さらに重要なことに、この実装には驚くべきことは何もありません。iter = std::move(rhs); ++iter;確かに、またはと言うことができ++(iter = std::move(rhs));ますが、なぜそれらがよりクリーンまたは高速になるのかについての議論は見当たりません。この実装は私にとって最も自然だと思います。

于 2013-12-22T19:31:46.063 に答える
-1

実際のオブジェクトからパラメーターに移動する関数を想像できます。

于 2013-06-06T22:18:58.723 に答える