2009-12-31

rvalue Reference is not an rvalue

rvalue referenceは、rvalueではない。私は今まで、これを深く考えたことはなかった。一体どういうことなのか。

int a ;

// Error
int && b = a ;

// OK. the same thing std::move() does.
int && c = static_cast< int && >(a) ;

// Error. Why?
int && d = c ;

bはエラーになるのは、常識でも理解できる。しかし、なぜdがエラーになるのか。まったく同じ型ではないか。また、こんな例もある。

// lvalue reference
void f( int & ) {}
// rvalue reference
void f( int && ) {}

int main()
{
    int x = 0 ;
    int && ref = std::move(x) ;

    // calls lvalue reference overload of f()
    f(ref) ;
}

なぜだろうか。rvalue referenceを渡しているのに、lvalue referenceのオーバーロードが呼ばれるとは、不思議である。さっそく、規格にあたろう。

8.5.3 References [dcl.init.ref] p5に、以下のように書いてある。

Otherwise, ... or the reference shall be an rvalue reference and the initializer expression shall be an rvalue.

rvalue referenceは、rvalueで初期化しなければならない。ところで、rvalue reference自身は、rvalueではない。lvalueである。よって、rvalue referenceを、rvalue referenceで初期化することは出来ない。

やれやれ、これで、C++0x本を書くときは、正しく説明することが出来る。自分でも、いまいちこの辺を理解していなかったので、ref-qualiferの説明のさいに、コードを間違えてしまったのだ。

5 comments:

  1. > int &&l d = c ;
    は、
    int && d = c ;
    ですね?

    ReplyDelete
  2. おっと、わざわざ自前の変換用ツールを使うのが面倒だったので、
    手動で書いたら失敗した。修正。

    ReplyDelete
  3. lvalueとして扱われるのはどうしてなんでしょうね?何か理由があるのでしょうけど。

    struct S1
    {
    std::vector vec;

    void operator=(S1&& r){ vec= r.vec; }
    }

    S1 Get()
    {
    S1 s1;
    return s1;
    }

    S1 s1= Get();

    ここで
    vec= std::move(r.vec)
    にする必要がありますよね、ムーブがかかるようにするためには。冗長に思えます。

    ReplyDelete
  4. なぜならば、リファレンスは使うからです。
    rvalue referenceの変数がrvalueだと解釈されるとすると、

    // コンストラクターなどを省略
    struct X { int * p ; } ;

    // Xを内部でムーブしてしまう関数
    void g( X && x ) ;

    void f( X && x )
    {
    g( x ) ; // rvalue referenceがrvalueだと、問題なく呼ばれてしまう
    *x.p = 0 ; // エラーになるかもしれない
    }

    関数fの本体で関数gを呼んだ場合、関数gの本体が、すでにxをムーブしてしまう、つまり、Xのメンバーであるポインターを横取りしてしまうかもしれません。
    とすると、関数gから戻った後のx.pは、妥当なオブジェクトを参照するポインターではなくなっているかもしれません。

    だから、rvalue referenceはlvalueなのです。

    ReplyDelete
  5. うーんなるほど。よくわかりました、ありがとうございます。

    vectorなどで構成された戻り値用の構造体で、デフォルトの代入演算子ではムーブがかかってほしいということも思ったんですが、まあ仕方ないですね。

    ReplyDelete

You can use some HTML elements, such as <b>, <i>, <a>, also, some characters need to be entity referenced such as <, > and & Your comment may need to be confirmed by blog author. Your comment will be published under GFDL 1.3 or later license with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.