2015-10-03-01-moveにも問題ありか - project-enigma

2015-10-03-01-moveにも問題ありか

>> Site top >> weblog >> 月別アーカイブ >> 2015年10月のlog >> 2015-10-03-01-moveにも問題ありか

最終更新日付:2015/10/03 09:11:24


moveにも問題ありか

2015 年 10 月 03 日

CL-STL には、swap 以外に get-setf-expansion を使っている場所として move マクロがある。ということは、当然同じ問題があることが予想されるわけで、なんていうか、こう‥‥‥あぁ面倒臭いなもう。頑張ろう。

今回は STL でどうできるかを先に書いてみよう。

#include <vector> 
#include <iostream>

int main( void ) {

    std::vector<int> vec;

    vec = std::move( std::vector<int>( {0, 1, 2, 3, 4, 5, 6} ) );

    for( int v : vec )
        std::cout << v << std::endl;

    return 0;
}

 

ポイントは、一時 vector オブジェクトを作成して std::move に直接渡している点だ。まだ動かないが、CL-STL だとどうなるのか見てみよう。繰り返すが、まだ動かないコードだ。

(let ((vec (new stl:vector)))
  (_= vec (stl:move (new stl:vector #{0 1 2 3 4 5})))
  (stl:for (v vec)
    (print v)))

 

えぇと、まぁなんだな。実際問題としてこう書きたいと思う理由があるかと言われると微妙なんだけど、コンパイルに通って動作するはずのコードが動かないってのは、やっぱり嫌なものだ。動かないというのは、上記コードにおける stl:move は以下のように展開されてしまうからだ。あ、見易さのために多少の整形はしてある(そしてリードマクロによる initializer-list の展開は戻してある)。

(stl:move (new stl:vector #{0 1 2 3 4 5}))

=> (CL-STL::__MOVE/1 (NEW CL-STL:VECTOR #{0 1 2 3 4 5}))

   => (LET* ((#:G1 #{0 1 2 3 4 5}))
        (IF (EQ (TYPE-OF (CL-STL::__NEW-VECTOR #:G1)) 'CL-STL::REMOVE-REFERENCE)
            (CL-STL::__NEW-VECTOR #:G1)
            (MAKE-INSTANCE 'CL-STL::REMOVE-REFERENCE
                           :CLOSURE (LAMBDA (&OPTIONAL (#:NEW (QUOTE #:TAG)))
                                      (IF (EQ #:NEW '#:TAG)
                                          (CL-STL::__NEW-VECTOR #:G1)
                                          (FUNCALL #'(SETF CL-STL::__NEW-VECTOR) #:NEW #:G1))))))

 

これは2つの点で問題がある。

特に2つめがマズい。多分、これを作った頃はシンボル変数を渡すことしか考えてなかったんだな。うん、要するになっちゃいなかったってワケだ。やれやれ。

というわけで、順番にやってみよう。まずは複数回の評価を避けることだ。これに対処した時点で、以下のようになった。

(stl:move (new stl:vector #{0 1 2 3 4 5}))

=> (CL-STL::__MOVE/1 (NEW CL-STL:VECTOR #{0 1 2 3 4 5}))

   => (LET* ((#:G1  #{0 1 2 3 4 5})
             (#:OBJ (CL-STL::__NEW-VECTOR #:G1)))
        (IF (EQ (TYPE-OF #:OBJ) 'CL-STL::REMOVE-REFERENCE)
            #:OBJ
            (MAKE-INSTANCE 'CL-STL::REMOVE-REFERENCE
                           :CLOSURE (LAMBDA (&OPTIONAL (#:NEW (QUOTE #:TAG)))
                                      (IF (EQ #:NEW '#:TAG)
                                          #:OBJ
                                          (FUNCALL #'(SETF CL-STL::__NEW-VECTOR) #:NEW #:G1))))))

 

で、次。今度は、setf 可能な場所でなければ move 実行時の「移動元削除」が空振りすればいいんだよな。だから以下のようになる。

(stl:move (new stl:vector #{0 1 2 3 4 5}))

=> (CL-STL::__MOVE/1 (NEW CL-STL:VECTOR #{0 1 2 3 4 5}))

   => (LET* ((#:G1  #{0 1 2 3 4 5})
             (#:OBJ (CL-STL::__NEW-VECTOR #:G1)))
        (IF (EQ (TYPE-OF #:OBJ) 'CL-STL::REMOVE-REFERENCE)
            #:OBJ
            (MAKE-INSTANCE 'CL-STL::REMOVE-REFERENCE
                           :CLOSURE (LAMBDA (&OPTIONAL (#:NEW (QUOTE #:TAG)))
                                      (IF (EQ #:NEW '#:TAG)
                                          #:OBJ
                                          #:NEW)))))

 

今回は修正した move マクロは掲載しないけれども、やってることは基本的にswap の時と同じだ。そしてそれゆえに、昨日と同じようにして助けを求めるわけだな。

引き続き、情報求む。

 

コメント

このページにコメントする

 

このページのタグ

Page tag : STLとその移植

Page tag : Common Lisp

 

 


Copyright(C) 2005-2017 project-enigma.
Generated by CL-PREFAB.