C++/標準テンプレートライブラリ(STL)

< C++

はじめに編集

最後に、STLは、言語を問わずあらゆる場面でよく用いられるデータ構造等を提供することを目的として導入されました。STLの中には、連想配列リストなどのデータ構造が定義されています。これらは、Perlや、Pythonなどの言語では標準のデータ構造として言語に組み込まれています。これらのデータ構造は、Cのプログラムでもよく用いられます。しかし、Cはこのようなデータ構造を言語自身の機能として持ってはいなかったため、Cを用いるプログラマは、プログラムを作成するときに、まず用いるデータ構造を作成する必要がありました。例えば、Apache httpdや、glibでは、STLで定義されるようなデータ構造が作成されています。 STLは作業の重複を省く意味でも積極的に用いるのがよいでしょう。ただし、これらのデータ構造を用いることだけが目的なら、PerlPythonなどを試してみることを勧めます。これらの言語はC++ほど速く実行されはしません。しかし、C++と比べて比較的簡潔にこれらを用いることが出来ます。そのため、STLはC++を用いる上でこれらのデータ構造が必要になった時に使われます。

string編集

Cではchar型の配列を用いる事で文字列を扱いましたが、 C++で標準ライブラリにあるstring型で文字列を扱います。

Cの機能を使った文字列操作には、 次のようなものがあります。

 #include <stdio.h>
 #include <string.h>
 
 int main()
 {
   char s1[] = "mojiretu";
   char s2[256];
 
   strcpy(s2, s1);    /* 文字列のコピー */
   printf("%s\n", s2);
   strcat(s2, s1);    /* 文字列の追加 */
   printf("%s\n", s2);
   printf("%zu\n", strlen(s2));    /* 文字列のサイズ */
 
   return 0;
 }

これをC++のstring型を使って書き直すと、 次のようになります。

 #include <iostream>
 #include <string>
 
 int main()
 {
   std::string s1 = "mojiretu";
   std::string s2;
 
   s2 = s1;    /* 文字列のコピー */
   std::cout << s2 << std::endl;
   s2 += s1;    /* 文字列の追加 */
   std::cout << s2 << std::endl;
   std::cout << s2.size() << std::endl;    /* 文字列のサイズ */
 
   return 0;
 }

string型にはchar型の配列を使うのにくらべて、 次のようなポイントがあります。

  1. 事前に文字列の最大数を指定する必要がなく、適宜メモリサイズが拡張される。
  2. コピーや追加等の操作を演算子により行える。
  3. 現在の文字列のサイズを、オブジェクトの中に持っている。

上記例では同一関数内ですのであまりメリットが見えないかもしれませんが、 ソフトウェアの規模が大きくなるにつれて利便性が見えてきます。

Cバージョンを関数分割すると、 次のようになります。

 #include <stdio.h>
 #include <string.h>
 
 void func(const char* s1)
 {
   char s2[256]; //<--s1の文字列サイズチェックがないとs2にコピー時オーバーフロー発生する可能性ある
 
   strcpy(s2, s1);    /* 文字列のコピー */
   printf("%s\n", s2);
   strcat(s2, s1);    /* 文字列の追加 */
   printf("%s\n", s2);
   printf("%zu\n", std::strlen(s2));    /* 文字列のサイズ */
 }
 
 int main()
 {
   char s1[] = "mojiretu";
 
   func(s1);
 
   return 0;
 }

この例ではmain()からしかfunc()は呼ばれないので、 事実上問題はありませんが、 func()に渡された文字列サイズをチェックしないと、 s2に対して範囲外へのアクセスを行う可能性があるため危険です。

これに対してC++バージョンを関数分割すると、 次のようになります。

 #include <iostream>
 #include <string>
 
 void func(const std::string& s1)
 {
   std::string s2;
 
   s2 = s1;    /* 文字列のコピー */
   std::cout << s2 << std::endl;
   s2 += s1;    /* 文字列の追加 */
   std::cout << s2 << std::endl;
   std::cout << s2.size() << std::endl;    /* 文字列のサイズ */
 }
 
 int main()
 {
   std::string s1 = "mojiretu";
 
   func(s1);
 
   return 0;
 }

string型への操作は必要に応じて内部のメモリサイズが増えるので、 引数で渡された文字列のサイズを気にせずコピーや追加を行うことが出来ます。