ぐぐるの頻出クエリを元にエントリを書いてみよう第一回

Filed in C/C++, prog

 ぐぐるからのお客さんの傾向を調べてたら頻出キーワードに「STL」があると判明。なのでSTLに関して何か書いてみようとおもいます。
 STLだけでは広すぎるので、STLと一緒に検索されたキーワードで最も多かった「スマートポインタ」を絡めてみます。
 さて、STLで検索してきてる人は、多分STLがなんであるかはご存知のはずですね。
 STLは標準C++に付属する標準ライブラリの一部で、テンプレートを用いたコンテナやアルゴリズムなんかのライブラリを指します。
 入門書の類などで特によく使われるのstringやvector、iostreamなんかもSTLに含まれるジェネリッククラスですね。
 さて、このSTLにはコンテナ、アルゴリズム、ユーティリティ、イテレータなどが含まれます。
 コンテナはデータ構造、アルゴリズムは言葉の通り、ユーティリティはちょっとした処理をテンプレート化した関数群、イテレータはデータ構造体を巡回する際などに使うポインタの代わりになるものです。
 最後に挙げたイテレータ、これってある意味スマートポインタなんですよね。
 スマートポインタと言えるほどの汎用性は無いんですが、STLコンテナの中を巡回することに関してはまさに「賢いポインタ」として動作してくれます。
 まずC言語での動的配列のイディオム。

    int *ida = (int*)malloc(sizeof(int) * 10);

 があった時、ポインタとポインタ演算を用いてこの配列の中身を頭から順番に設定していくコードは以下のようになります。

    int *ip = ida;
    int i;
    for(i = 0; i < 10; ++ip, ++i){
        /* something() はint型の何らかの値を返する関数 */
        *ip = something();
    }

 これを、C++での動的配列のイディオムで表現すると。

    std::vector<int> ida(10);
    for(std::vector<int>::iterator ip = ida.begin();
         ip != ida.end();
         ++ip){
        // something() はint型の何らかの値を返す関数
        *ip = something();
    }

 ipに対する操作に着目するととても似てますね。イテレータはポインタを模して作られているのです。
 しかしこれだけだとありがたみがわかりませんね。そこでリンクリストに関しても見てみましょう。
 C言語だと、典型的なリンクリストの巡回は以下のようになります。

    typedef struct list_tag{
        int value_;
        struct list_tag *next_;
    } List;
    /* (snip) */
    List *iter;
    for(iter = Data; iter != DataEnd; iter = iter->next_){
        /* something() はint型の引数を受け取る関数 */
        something(iter->value_);
    }

 C++で書いてみましょう。

    std::list<int> Data;
    // (snip)
    for(std::list<int>::iterator iter = Data.begin()
         iter != Data.end();
         ++iter){
        // something() はint型の引数を受け取る関数
        something(*iter);
    }

 iterに着目したとき、C言語版よりも楽になった感じです。なにより、C++版だと、iterに対する操作は本質的にvectorの場合と変わってません。
 ただのポインタの場合、データ構造ごとに違う探索操作をしなければならないところを、実際の動作を隠蔽して統一的な操作で行ってしまうのがイテレータの魅力です。ことコンテナの探索に関しては立派にスマートポインタと言えます。
 しかし、検索で来てる方々は、こういったものではなくて汎用のスマートポインタを探してますよね。
 STLにも一つ、汎用のスマートポインタがあります。auto_ptrがそれです。もちろんデストラクト時にちゃんとdeleteしてくれます。
 auto_ptrは破壊的スマートポインタと呼ばれる方法で実装されたスマートポインタです。あるポインタについて、一つだけ所有権を認めます。
 例えば以下のようにすると、aは0 (NULL) を指し、aの指していた領域をbが指すようになります。

    auto_ptr<int> a(new int(10));
    auto_ptr<int> b(a);
 あるいは
    auto_ptr<int> a(new int(10));
    auto_ptr<int> b;
    b = a;

 ソース側の状態を破壊するので破壊型という訳です。しかしこれなら確かにリークはありません。
 しかしこの方法、割と問題あるんですよね。例えば。

// 参照渡しのつもりでポインタ型引数を受け取って二倍にして引数経由で値を返す関数
void Double(int* ptr){ *ptr *= 2; }
// 生のポインタは怖いからスマートポインタ用にオーバーロード
void Double(auto_ptr<int> ptr){ *ptr *= 2; }
int main(){
    int i = 20;
    auto_ptr<int> ptr(new int(10));
    Double(&i);
    Double(ptr);
    cout << i << ", " << *ptr << endl; // 不正な参照はがし
    return 0;
}

 Double(int*)はうまく動きますが、Double(auto_ptr<int>)はうまく動きません。
 Double(auto_ptr<int>)では、auto_ptr<int>を値渡ししています。なので、実引数はコピーされるのです。auto_ptrではコピーが発生すると、ソース側が破壊されるので、関数本体に入った時点で既に呼び出し側のptrには0が設定されています。なので出力行での参照はがしは不正なメモリアクセスとなります。なので上記のような場合は参照で渡しましょう。
 また、ポインタを保持するコンテナではポインタの代わりにauto_ptrを使おうとすると痛い目に遭うかもしれません。

    vector<auto_ptr<int> > iapv1;
    vector<auto_ptr<int> > iapv2;
    iapv1.push_back(new int(10));
    iapv1.push_back(new int(20));
    iapv2 = iapv1; // ここでコピーが発生。iapv1の保持するポインタが破壊される
    *iapv1[0] = 100; // 既にiapv1[0]はヌルポインタなのでエラー

 正直知らないと気付きません(´・ω・`)
 破壊型という特性故にauto_ptrは使いづらいと言う評価を受けるようです。長月もスマートポインタをご所望の方はBoostのshared_ptrを使ったほうが良いかと思います。
 それでは今回はここまで。また気が向けばやってみます。当日記に出てきたキーワードで、何か知りたいことがある方はぐぐる経由でアクセスしまくるといいかもですよ? であであノシ
 #ちなみに最頻出クエリは「hidew」でした(絶爆) おめでたうw>hidewさん


Feedback

Comments

2 Responses to “ぐぐるの頻出クエリを元にエントリを書いてみよう第一回”
  1. hidew より:

    >#ちなみに最頻出クエリは「hidew」でした(絶爆) おめでたうw>hidewさん
    がびーん(笑)
    私の所は、ats さんのアンテナ経由の人がほとんどで、ネタになるような面白検索はあまりないですね(寂)

  2. 長月葵 より:

    あぁいえいえ、blogだけならSTLとLokiが最頻出なんですけどね。
     ほむぺの方まで含めるとリンクページのコメントとかでhidewさんが最頻出になるんですよ。
     多いのは「hidew 迷宮」ですね。


Warning: sprintf() [function.sprintf]: Too few arguments in /home/users/2/lolipop.jp-dp07042166/web/wordpress/wp-includes/widgets.php on line 1042
Oenology Post Formats
Click to view/hide

Warning: sprintf() [function.sprintf]: Too few arguments in /home/users/2/lolipop.jp-dp07042166/web/wordpress/wp-includes/widgets.php on line 1042
Posts Calendar
Click to view/hide
2005年3月
« 2月   4月 »
 12345
6789101112
13141516171819
20212223242526
2728293031  

Warning: sprintf() [function.sprintf]: Too few arguments in /home/users/2/lolipop.jp-dp07042166/web/wordpress/wp-includes/widgets.php on line 1042
アーカイブ
Click to view/hide

Warning: sprintf() [function.sprintf]: Too few arguments in /home/users/2/lolipop.jp-dp07042166/web/wordpress/wp-includes/widgets.php on line 1042
最近の投稿
Click to view/hide