SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

STL/CLRツアーガイド

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


STL/CLRコンテナの要素は3通り

 BCLコレクションは参照ハンドルもしくは値(value class)のいずれかをその要素とします。STL/CLRコンテナはそれに加え、参照そのものを要素とすることができます。

 コンテナの挙動を調べるため、以下に示すref classを用意しました。

ref class RefClass
public ref class RefClass {
private:
  int value_;
public:
  // コンストラクタ(デフォルト)
  RefClass()
    { Console::WriteLine(L"RefClass.ctor()"); }
  // コンストラクタ(コピー)
  RefClass(const RefClass% r) : value_(r.value_)
    { Console::WriteLine(L"RefClass.ctor(const RefClass%)"); }
  RefClass(RefClass^ r) : value_(r->value_)
    { Console::WriteLine(L"RefClass.ctor(RefClass^)"); }
  // コンストラクタ(単項)
  RefClass(int n) : value_(n)
    { Console::WriteLine(L"RefClass.ctor(int)"); }
  // デストラクタ
 ~RefClass()
    { Console::WriteLine(L"RefClass.dtor()"); }
  // ファイナライザ
 !RefClass()
    { Console::WriteLine(L"RefClass.fin.()"); }
  // コピー演算
  RefClass% operator=(const RefClass% r) {
    value_ = r.value_;
    Console::WriteLine(L"RefClass.op=(const RefClass%)");
    return *this;
  }
  // プロパティ
  property int Value {
    int get() { return value_; }
    void set(int n) { value_ = n; }
  }
};

 STL/CLRコンテナ:vector<RefClass^>に要素を追加し、その挙動を調べてみましょう。

STL/CLRコンテナ(参照ハンドル)
// STL/CLRコンテナ: vectorの場合(参照ハンドル)
{
  Console::WriteLine("---------- vector<RefClass^>");
  cliext::vector<RefClass^> container;
  RefClass^ rc = gcnew RefClass();
  for ( int i = 0; i < 3; ++i ) {
    rc->Value = i;
    container.push_back(rc);
  }
  for each ( RefClass^ item in container ) {
    Console::WriteLine(item->Value);
  }
  Console::WriteLine("---------------------------");
}
実行結果
---------- vector<RefClass^>
RefClass.ctor()
2
2
2
---------------------------
RefClass.fin.()

 要素のValueプロパティを書き変えながら挿入しているにもかかわらず、列挙された値はどれも同じになっています。コンテナが内包するのが参照ハンドルなので、内包される要素はどれもみな一つの参照を指しているからです。BCLコレクションでも同じ挙動を示します。

BCLコレクション(参照ハンドル)
// BCLコレクション: List の場合
{
  Console::WriteLine("---------- List<RefClass^>");
  List<RefClass^> container;
  RefClass^ rc = gcnew RefClass();
  for ( int i = 0; i < 3; ++i ) {
    rc->Value = i;
    container.Add(rc);
  }
  for each ( RefClass^ item in container ) {
    Console::WriteLine(item->Value);
  }
  Console::WriteLine("---------------------------");
}

 STL/CLRコンテナには参照ハンドルではなく、参照そのものを要素とすることができます。このときvector<RefClass>のように、要素の型にハンドルを示す ^ が付きません。

STL/CLRコンテナ(参照)
// STL/CLRコンテナ: vectorの場合(参照)
{
  Console::WriteLine("---------- vector<RefClass>");
  cliext::vector<RefClass> container;
  RefClass^ rc = gcnew RefClass();
  for ( int i = 0; i < 3; ++i ) {
    rc->Value = i;
    container.push_back(rc);
  }
  for each ( RefClass^ item in container ) {
    Console::WriteLine(item->Value);
  }
  Console::WriteLine("---------------------------");
}
実行結果
---------- vector<RefClass>
RefClass.ctor()
RefClass.ctor(RefClass^)
RefClass.ctor(RefClass^)
RefClass.ctor(RefClass^)
0
1
2
---------------------------
RefClass.dtor()
RefClass.dtor()
RefClass.dtor()
RefClass.fin.()

 参照を要素とした場合、要素の挿入時にコピー・コンストラクタでコピーが生成され、そのコピーがコンテナ内に格納されています。

STL/CLRコンテナはBCL interfaceを実装している

 冒頭にも述べたように、STL/CLRコンテナはBCLのコレクションinterfaceを実装しています。これによってアセンブリの外からinterfaceを介してアクセスが可能です。

 STL/CLRコンテナのBCL-interface実装はprivate部に隠されているので直接触ることができませんが、interfaceにキャストすることで例えばvector<T>IList<T>として扱うことができます。

STL/CLRコンテナのBCL-interface実装
#include <cliext/vector>

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

int main() {
  cliext::vector<String^> sv;
  IList<String^>^ ils = %sv; // BCL-interfaceにキャスト
  ils->Add(L"zero"); // 末尾に追加
  ils->Add(L"two");
  ils->Add(L"THREE");
  ils->Insert(1,L"one"); // 挿入
  ils[3] = L"three"; // インデクサで3番目を更新
  ils->RemoveAt(2); // 削除
  // IEnumerable<T> を実装するので for each で列挙可能
  for each ( String^ item in sv ) {
    Console::WriteLine(item);
  }
  ils->Clear(); // 全要素削除
  Console::WriteLine(L"要素数: {0}", ils->Count);
}
実行結果
zero
one
three
要素数: 0

次のページ
array<T>でalgorithmを使うには...

この記事は参考になりましたか?

特集記事連載記事一覧

もっと読む

この記事の著者

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

C++に首まで浸かったプログラマ。Microsoft MVP, Visual C++ (2004.01~2018.06) "だった"りわんくま同盟でたまにセッションスピーカやったり中国茶淹れてにわか茶...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/2664 2008/07/08 06:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー