■STLメモ



テンプレート


コンパイル時に型が決まるらしい。いろんな型を入れるサンプル。

#include <iostream>

using namespace std;
 
 
template <class MyTemplate>
MyTemplate TGetMax( MyTemplate &a, MyTemplate &b,  MyTemplate &c ){ 
    MyTemplate &x = a >b? a:b;
    MyTemplate &y = b >c? b:c;
    return x > y? x:y;
}

int main(void){

   int na=100, nb=200, nc=300;
   char cha='A', chb='B', chc='C';
   double da=1.1, db=1.2, dc=1.3;

    cout << TGetMax( na, nb, nc ) << endl;
    cout << TGetMax( cha, chb, chc ) << endl;
    cout << TGetMax( da, db, dc ) << endl; 

    return 0;
}

うまく使うと便利かも。なお、MyTemplateはよくTとして使われる。



Cの配列にSTLを使用


Cでの配列にSTLを使う例。

#include <iostream>
#include <algorithm>

using namespace std;

template <class T>
class MyTemplateArray{
   public:
       T array[5];

       void SetValue(int item, T val);
       T &GetValue(int item);
};

template <class T>
void MyTemplateArray<T>::SetValue(int item, T val){
   if( item > 4 || item < 0 ){
       cout << "Error: Item is out of range!!" << endl;
       return;
   }
   array[item] = val;
}

template <class T>
T &MyTemplateArray<T>::GetValue(int item){
   if( item > 4 || item < 0 ){
       cout << "Error: Item is out of range!!" << endl;
       return array[0];
   }
   return array[item];
}

int main(){
   MyTemplateArray<int> mt;
   
   // set array
   for(int i=0; i<5; i++){ mt.SetValue( i, rand() ); }
   
   // print
   for(int i=0; i<5; i++){ cout << mt.GetValue(i) << ' '; } cout << endl;
    
  return 0;
}

しかし、このような使い方は一般的ではない。


vectorによる2次元配列


vectorで2次元配列を作る。1つ目は直に値を入れる方法、2つ目はvectorをプッシュする方法。


#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>

using namespace std;


int main( void ){

    // array1
    cout << "===========array1\n";
    vector< vector<int> > array;
    // resize
    int size=4;
    array.resize( size );
    for(int i = 0; i<size; i++){ array[i].resize( size ); }

   // set
   for(int i=0; i< size;i++){
       for(int j=0; j<size; j++){
           array[i][j] = (i+1)*(j+1);
       }
   }
   // print
   for(int i=0; i< array.size();i++){
       for(int j=0; j<array[i].size(); j++){ cout << array[i][j] << " "; }
       cout << endl;
   }

   // array2
   cout << "===========array2\n";
   vector< vector<int> > array2;
   vector<int> temp;

   // set
   for(int i=1; i<5; i++){
       for(int j=1; j<5; j++){
           temp.push_back( i * j );
       }
       array2.push_back( temp );
       temp.erase( temp.begin(), temp.end() );
   }
   // print
   for(int i=0; i< array2.size();i++){
       for(int j=0; j<array2[i].size(); j++){ cout << array2[i][j] << " "; }
       cout << endl;
   }
 
    cout << "===========\n";

   // push
   array[0].push_back(5);
   // print
   cout << endl << "push 5" << endl;
   for(int i=0; i< array.size();i++){
       for(int j=0; j<array[i].size(); j++){ cout << array[i][j] << " "; }
       cout << endl;
   }
 
    
   return 0;
}



関数オブジェクト


関数オブジェクト
関数のように呼び出すことのできるオブジェクト。operator()()演算子関数を実装したクラスオブジェクト。

らしい。関数オブジェクトを使った例。

#include <iostream>
include <vector>
#include <functional>
#include <algorithm>

using namespace std;

template <class T>
struct ShowData : public unary_function<T, void>{
    void operator()(T n){ 
        cout << n << ' '; 
    }
};

int main( void ){

    vector<int> array;

    // set
    for(int i=0; i<5; i++){
       array.push_back(i);
    }

    // show data
    for_each(array.begin(), array.end(), ShowData<int>() );
    cout << endl;
 
    return 0;
}

おぉ、これは便利。

動的に2次元配列


#include <iostream>

using namespace std;


int main(void){

    int N=10;
    double** a = new double*[N];
    for(int i=0;i <N; i++){
      a[i] = new double[N];
    }

    a[0][1] = 1.0;
    printf("%lf\n", a[0][1] );

    // delete
    for(int i=0;i <N; i++){
       delete[] a[i];
    }
    delete[] a;

    return 0;
}

こうしないと、環境によってはコンパイルエラー。
もう少し改良したもの。

#include <iostream>

using namespace std;

int main(void){

    int col=3;
    int row=2;
    int** a = new int*[row];
    for(int i=0;i <row; i++){
      a[i] = new int[col];
    }

    a[0][0] = 0;
    a[0][1] = 1;
    a[0][2] = 2;
    a[1][0] = 3;
    a[1][1] = 4;
    a[1][2] = 5;

    for(int i=0; i<row; i++){
        for(int j=0; j<col; j++){
            printf("%d ", a[i][j] );
        }
        printf("\n");
    }
 

    // delete
    for(int i=0;i <row; i++){
       delete[] a[i];
    }
    delete[] a;

    return 0;
}



要素をコピー

vectorのdataからtempにコピーするには、次のように行う。
tempを定義する際に、サイズを書き忘れるとbus errorというエラーになる。

   vector<int> temp( data.size() );
   copy( data.begin(), data.end(), temp.begin() );



要素の重複を除く

vector<int>のlistの重複を除いたuniq_dataというのを作る。上のコピーを使う。

   vector<int> uniq_data( list.size() );

   copy( list.begin(), list.end(), uniq_data.begin() );
   sort( uniq_data.begin(), uniq_data.end() );
   vector<int>::iterator ite = unique( uniq_data.begin(), uniq_data.end() );
   uniq_data.erase( ite, uniq_data.end() );

これで重複しないものができる。



コンマで分割

コンマ区切りのテキストをint型のvectorに入れて返す関数。perlのsplitみたいなもの。

vector<int> splitStringWithComma( string& input ){

    int num = 0;
    string str = "";
    vector<int> list;


    for(int i=0; i<(int)input.size(); i++){

        //cout << input[i] << endl;

        if( input[i] == ',' ){
            //cout << "str= " << str << endl;
            istringstream iss( str );
            iss >> num;

            list.push_back( num );
            str = "";

            continue;
        }



        str += input[i];

    }
    /* last number */
    istringstream iss( str ); iss >> num;
    list.push_back( num );


    return list;
}



最後の一つを入れるのにもうちょっときれいな書き方はないかなぁ~。





クラスの分割ファイル


STLとは関係ないけど、テンプレとして。

node.h

#ifndef _INC_NODE_
#define _INC_NODE_

#include <iostream>
#include <vector>
#include <string>

using namespace std;

class Node {

private:
    int ID;
    string name;

public:
    /* constructor */
    Node();
    ~Node();
 
    /* set */
    void setID( int );
    void setName( string );

    /* get */
    int getID();
    string getName();

};

#endif



node.cpp

#include <iostream>
#include <vector>
#include <string>

#include "node.h"

using namespace std;

/* constructor */
Node::Node(){ ID = -1; name = ""; }

/* destructor */
Node::~Node(){ }


/* set */
void Node::setID(int i){
    if( i >= 0 ){ ID = i; }
    else { cout << "set ID error" << endl; }
}

void Node::setName(string str){
    if( str != "" ){ name = str; }
    else { cout << "set Name error" << endl; }
}

/* get */
int Node::getID(){ return ID; }
string Node::getName(){ return name; }



nodetest.cpp

#include <iostream>
#include <vector>
#include <string>


#include "node.h"

using namespace std;

int main(void){

    Node node1;
    node1.setID(0);
    node1.setName("root");


    cout << node1.getID() << " " << node1.getName() << endl;


    return 0;
}



要素の挿入

vector<int>に要素を挿入する。よくあるサンプルは以下のようなもの。
 vector<int> list;
 list.push_back(1);
 list.push_back(2);
 list.push_back(4);
 
 vector<int>::iterator ite = list.begin();
 list.insert( ite+2, 3 );      /* 0から数えて、2番目の前(=4)に挿入 */

この方法で、連続的にデータを挿入するときには、少し注意が必要。
それは、毎回iteratorをセットすること。例えば、
for(int i=0; i<(int)a.size(); i++){
    ite = b.begin();
    if( a[i] == -1 ){ b.insert( ite+i, -1 );  }
 }

というようにする。




要素の削除

リストから-1をすべて削除する例。

  int pos = 0;
  vector<int>::iterator ite = list.begin();

  for(int i=0; i<(int)list.size(); i++){

       if( list[i] == -1 ){
           pos = i;
           ite = list.begin();
           for(int j=0; j<pos; j++){
               ite++;
           }
           list.erase( ite );
           i = pos-1;
       }

   }


最大・最小を求める

最大・最小を求めるときに便利な*max_element()。しかし、要素が0のものに
対して行うとbus errorになるので注意。

if( (int)list.size() != 0 ){
  int max = *max_element( list.begin(), list.end() );
}

とする。


vectorへのアクセス

当たり前だが、空のvectorにアクセスすると、セグメンテーションのエラー。
普通はforループでアクセスするため、(int)list.size()のような形で個数をチェックしている。
しかし、直接n番目の要素にアクセスしようとするときに注意が必要。特に、二次元配列のn行目にアクセスするとき。
こうするのがいいのかな?

int target_line = 10;
if( (int)array.size() != 0 ){
  for(int j=0; j<(int)array[target_line].size(); j++){
    cout << array[target_line][j] << " ";
  }
} else {
  cout << "array is empty!!" << endl;
}









参考文献:柏原正三「標準C++ STLの基礎知識」、アスキー2001

タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

最終更新:2007年02月01日 18:40