2015-10-14-01-STL書籍の掲載コードをCL-STLで書いてみよう-9 - project-enigma

2015-10-14-01-STL書籍の掲載コードをCL-STLで書いてみよう-9

>> Site top >> weblog >> 月別アーカイブ >> 2015年10月のlog >> 2015-10-14-01-STL書籍の掲載コードをCL-STLで書いてみよう-9

最終更新日付:2015/10/14 09:00:36


STL書籍の掲載コードをCL-STLで書いてみよう-9

2015 年 10 月 14 日

引き続き Effective STL、今回は第30項の「出力先範囲の大きさを確認しよう」から。

この項では、まずやっちゃいけない例から始まる。transform で新しいシーケンスを生成するが、格納先コンテナの end を指定しちゃってるパターンだ。

int transmogrify( int x );

std::vector<int> values;
...
std::vector<int> results;
std::transform( values.begin(), values.end(), results.end(), transmogrify);    // BUG!

 

CL-STL で同じミスをしでかすことはもちろん可能だ。以下のようになる。これを実行した場合の結果は未定義の領域なので、何が起きてもびっくりしないように。

(defun transmogrify (x) (* x 2))

(let ((values  (new stl:vector #{0 1 2 3 4 5 6 7 8 9}))
      (results (new stl:vector)))
  (stl:transform (stl:begin values) (stl:end values)
                 (stl:end results) #'transmogrify))    ;; BUG!

 

で、続いてこれを正しく修正したコードが提示されるわけだ。具体的には、出力先の反復子でなく後方挿入反復子を指定するところが変更点。

std::vector<int> results;
std::transform( values.begin(), values.end(),
                std::back_inserter(results), transmogrify);

 

これに対応する CL-STL コードは以下の通り。これなら実行できる。

(let ((values (new stl:vector #{0 1 2 3 4 5 6 7 8 9}))
      (results (new stl:vector)))
  (stl:transform (stl:begin values) (stl:end values)
                 (stl:back-inserter results) #'transmogrify)
  (stl:shrink-to-fit results)
  (stl:data results))

;=> #(0 2 4 6 8 10 12 14 16 18)


 

続いて、front_inserter を使用する話に移る。push_front ができなければならないので、対象は dequelist だ。

std::list<int> results;
std::transform( values.begin(), values.end(),
                std::front_inserter(results), transmogrify);

 

対応する CL-STL のコードは以下。書籍でも説明されている通り、逆順に入ることになる。

(let ((values (new stl:vector #{0 1 2 3 4 5 6 7 8 9}))
       (results (new stl:list)))
   (stl:transform (stl:begin values) (stl:end values)
                  (stl:front-inserter results) #'transmogrify)
   (stl:for (v results) (format t "~A " v)))

;=> 18 16 14 12 10 8 6 4 2 0 
    NIL

 

これを解決するには、逆方向反復子を使用する。begin/end のかわりに rbegin/rend を使用しているだけだ。

(let ((values (new stl:vector #{0 1 2 3 4 5 6 7 8 9}))
       (results (new stl:list)))
   (stl:transform (stl:rbegin values) (stl:rend values)
                  (stl:front-inserter results) #'transmogrify)
   (stl:for (v results) (format t "~A " v)))

;=> 0 2 4 6 8 10 12 14 16 18 
    NIL

 

さらに続いて insert_iterator を使う話。すでにシーケンスを保持しているresults の中央に要素を割り込ませる。

vector<int> values;
...
vector<int> results;
...
std::transform( values.begin(), values.end(),
                std::inserter( results, results.begin() + results.size() / 2),
                transmogrify);

 

対応する CL-STL コードは以下。実はここで insert-iterator にバグがあることが発覚したが、幸いすぐに原因が判明したので修正済み。

(let ((values  (new stl:vector #{0 1 2 3 4}))
      (results (new stl:vector 6 :x)))
  (stl:transform (stl:begin values) (stl:end values)
                 (stl:inserter results (_+ (stl:begin results)
                                           (/ (stl:size results) 2)))
                 #'transmogrify)
  (stl:shrink-to-fit results)
  (stl:data results))

;=> #(:X :X :X 0 2 4 6 8 :X :X :X)

 

‥‥‥まぁひとまずはこんなところだろうか。このあと、reserve を使ったとしても「容量が増えた」だけで「要素数が増えたわけではない」ため、やっぱり挿入反復子を使わなきゃダメだよ、という話が出る。まぁそのあたりのコトはいいだろう。今回はこれでおしまい。

 

このシリーズのこれまでのエントリ

 

コメント

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

 

このページのタグ

Page tag : STLとその移植

Page tag : Common Lisp

 

 


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