CodeZine(コードジン)

特集ページ一覧

STL/CLRツアーガイド

STL/CLRの特徴と、BCLと連携するためのヘルパ関数/クラス

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加
2008/07/07 14:00

標準C++ライブラリの構成要素の一つであるSTLとの互換性を重視したmanagedなテンプレート・ライブラリ「STL/CLR]。C++プログラマにはなじみのあるSTLの使い心地に加えて.NET FrameworkのBCL(Basic Class Library)との親和性が考慮されています。

目次

はじめに

 赤坂さんが面白いアーティクルを寄稿してくれました。

 Visual C++ 2008で新たに追加されたSTL/CLRはなんとも不思議なライブラリです。.NET FrameworkのBCL(Base Class Library)が提供するSystem.Collections.Generic名前空間で定義されたBCLコレクションと同等(それ以上?)のクラス群を提供し、それらは標準C++ライブラリに組み入れられたSTLとの高い互換性を実現しています。その代償として、templateで実装されているためにアセンブリの外に持ち出すことができません(C#やVBはtemplateを理解できませんから)。

 赤坂さんのアーティクルでは、STL/CLRコンテナがinterfaceを実装していることを利用してアセンブリ外からinterfaceとしてアクセスする方法について解説しています。

 本稿ではSTL/CLRの持つさまざまな特徴と、STL/CLRがBCLコレクションのために提供するヘルパ関数/クラスについて解説します。

STL/CLRの特徴

 と、その前に。STL/CLRを使ったコードをコンパイルすると、次のようなエラー・メッセージが現れます:

fatal error C1107: アセンブリ 'Microsoft.VisualC.STLCLR.dll' がみつ
かりませんでした: /AI または LIBPATH 環境変数を使用してアセンブリ検
索パスを指定してください。

 このエラーは、ソースコードが間接的に#includeしているヘッダ<xutility>内で#using <Microsoft.VisualC.STLCLR.dll>されており、コンパイラがアセンブリ「Microsoft.VisualC.STLCLR.dll」を見つけられなかったことに起因します。「Microsoft.VisualC.STLCLR.dll」はVC++がインストールされたディレクトリのlibサブ・ディレクトリにあるので、プロジェクト・プロパティで[#using参照の解決]に$(VCInstallDir)libを設定することでエラーを解決できます。

#using参照の解決
#using参照の解決

 さて、それではSTL/CLRにまつわるさまざまなトピックを紹介していきましょうか。

STL/CLRはSTLと同様のクラス/関数を提供する

 STL/CLRが作られた最大の目的が「C++/CLIにSTLを提供する」ことですから、これは至極当然のことです。クラス名/関数名はもちろんのこと、ヘッダ名までSTLと同じ名前が用いられています。STLと異なるのは名前空間がstdではなくcliextであること、ヘッダがcliextサブディレクトリに置かれていること、などなど。

STL(C++)だと...
#include <iostream>
#include <vector>
#include <string>

int main() {
  std::vector<std::string> sv;
  sv.push_back("zero"); // 末尾に追加
  sv.push_back("two");
  sv.push_back("THREE");
  sv.insert(sv.begin()+1, "one"); // 挿入
  sv[3] = "three"; // operator[]で3番目を更新
  sv.erase(sv.begin()+2); // iteratorの指す要素を削除
  // 全要素を列挙
  for ( std::vector<std::string>::iterator iter = sv.begin();
        iter != sv.end(); ++iter ) {
    std::cout << *iter << std::endl;
  }
  sv.clear(); // 全要素削除
  std::cout << "要素数: " << sv.size() << std::endl;
}

 このC++コードをSTL/CLRを使ってC++/CLIにポートすると次のようになります。STLとの互換性が十分考慮されているので、STLになじみのあるC++プログラマには敷居の低いライブラリに仕上がっています。

STL/CLR(C++/CLI)だと...
#include <cliext/vector>

using namespace System;

int main() {
  cliext::vector<String^> sv;
  sv.push_back(L"zero"); // 末尾に追加
  sv.push_back(L"two");
  sv.push_back(L"THREE");
  sv.insert(sv.begin()+1,L"one"); // 挿入
  sv[3] = L"three"; // operator[]で3番目を更新
  sv.erase(sv.begin()+2); // iteratorの指す要素を削除
  // 全要素を列挙
  for ( cliext::vector<String^>::iterator iter = sv.begin();
        iter != sv.end(); ++iter ) {
    Console::WriteLine(*iter);
  }
  sv.clear(); // 全要素削除
  Console::WriteLine(L"要素数: {0}", sv.size());
}

 STL/CLRコンテナの特徴の一つにメソッドの統一性があります。これもSTLとの互換性によるものです。シーケンシャルな集合から特定の要素を見つけ、そこから集合の最後までを列挙するコードを考えてみましょう。.NET FrameworkのBCLコレクション:List<T>(可変長配列)とLinkedList<T>(双方向リスト)を使ったコードはそれぞれ次のようになります。

BCLコレクション(List,LinkedList)による検索と列挙
using namespace System;
using namespace System::Collections::Generic;

bool is_three(String^ s) { return s == L"three"; }

int main() {
  array<String^>^ source = gcnew array<String^>
    { L"zero", L"one", L"two", L"three", L"four", L"five" };

  /*
   * 集合から"three"を探し、そこから最後までを列挙する
   */
  // BCLコレクション: List と LinkedList の場合:
  { // BCL List<String^>
    List<String^> container(source);
    // 何番目にあるかを調べ
    int result = container.FindIndex(
      gcnew Predicate<String^>(&is_three));
    if ( result >= 0 ) { // 見つかったら
      while ( result < container.Count ) { // そこから最後まで列挙
        Console::WriteLine(container[result]);
        ++result;
      }
    }
  }
  { // BCL LinkedList<String^>
    LinkedList<String^> container(source);
    // 目的の値を指す LinkedListNode を手にいれ、
    LinkedListNode<String^>^ result = container.Find(L"three");
    while ( result != nullptr ) { // そこから最後まで列挙
      Console::WriteLine(result->Value);
      result = result->Next;
    }
  }
}

 List<T>LinkedList<T>では要素の検索と列挙のやり方が異なっています。STL/CLRコンテナではどうでしょうか。

STL/CLRコンテナ(vector,list)による検索と列挙
#include <cliext/vector>
#include <cliext/list>
#include <cliext/algorithm>

using namespace System;
using namespace System::Collections::Generic;

bool is_three(String^ s) { return s == L"three"; }

int main() {
  array<String^>^ source = gcnew array<String^>
    { L"zero", L"one", L"two", L"three", L"four", L"five" };

  /*
   * 集合から"three"を探し、そこから最後までを列挙する
   */
  // STL/CLRコンテナ: vector と list の場合
  { // STL/CLR vector
    cliext::vector<String^> container(source);
    // 目的の値を指すイテレータを手にいれ
    cliext::vector<String^>::iterator iter =
      cliext::find(container.begin(), container.end(),
                   gcnew String(L"three"));
    while ( iter != container.end() ) { // そこから最後までを列挙
      Console::WriteLine(*iter);
      ++iter;
    }
  }
  { // STL/CLR list
    cliext::list<String^> container(source);
    // 目的の値を指すイテレータを手にいれ
    cliext::list<String^>::iterator iter =
      cliext::find(container.begin(), container.end(),
                   gcnew String(L"three"));
    while ( iter != container.end() ) { // そこから最後までを列挙
      Console::WriteLine(*iter);
      ++iter;
    }
  }
}

 vector<T>,list<T>の検索と列挙はどちらもまったく同じ書式になっていますね。


  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • επιστημη(エピステーメー)

    C++に首まで浸かったプログラマ。 Microsoft MVP, Visual C++ (2004.01~2018.06) "だった"り わんくま同盟でたまにセッションスピーカやったり 中国茶淹れてにわか茶人を気取ってたり、 あと Facebook とか。 著書: - STL標準...

All contents copyright © 2005-2020 Shoeisha Co., Ltd. All rights reserved. ver.1.5