SHOEISHA iD

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

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

japan.internet.com翻訳記事

C++開発者のためのRubyガイド

同じ動作をするプログラムでC++とRubyの実装を比較する

  • X ポスト
  • このエントリーをはてなブックマークに追加

ダウンロード サンプルソース (2.4 KB)

C++開発者がRubyを学ぶには覚悟が必要です。この強力かつシンプルな言語に慣れてしまったら、C++に戻ることが辛くなるかもしれないからです。

  • X ポスト
  • このエントリーをはてなブックマークに追加

はじめに

 あなたがC++開発者で、最近Rubyプログラミング言語に関するあらゆる情報が気になっているとしたら、この記事はまさにあなたにうってつけです。ここでは、C++とRubyの重要な違いを概説し、それぞれの言語で実装された小さいながらも完全なサンプルアプリケーションを紹介します。

 ただし、Rubyを覚えることがストレスになる可能性があることは、あらかじめご了承ください。この強力かつシンプルな言語に慣れてしまったら、C++に戻ることが辛くなるかもしれません。

高レベル言語の比較と実行サンプル

 C++は静的に型付けされたコンパイル言語であり、ハイブリッド型オブジェクト指向の性質を備えています。「静的に型付けされた」とは、すべての式と変数の型がコンパイル時にわかっており、プログラムの実行前に重要な正確性チェックを行えることを意味します。「ハイブリッド型オブジェクト指向」とは、この言語がオブジェクトでないプリミティブ型(int型やfloat型など)を定義していることと、オブジェクトの外に関数を記述できることを意味しています。

 Rubyというプログラミング言語は、コードをすばやく簡単に書けるようにすることを目指して考案されたものです。C++とは異なり、きわめて動的なインタプリタ型言語で、一連の強力なライブラリが含まれます。一般的にはスクリプト言語と呼ばれていますが、これは純粋なオブジェクト指向の言語であり、汎用アプリケーションに対応するための表現力を十分に備えています。

 Rubyでは、変数を宣言する必要がなく、各ステートメントで変数の型を自由に変更できます。したがって、たとえば次のコードでは変数xの型をFixNum(ネイティブのマシンワードに収まる長さの整数)からString、そしてArrayに変更していますが、これはRubyコードの完全に正当なシーケンスです。

x = 10
x += 4
x = "My String"
x = [1, "My String", Hash.new ]

 Rubyの重大な弱点は、インタプリタを使用することです。Rubyの実行時のパフォーマンスは、C++のようなコンパイル言語とは比較になりません。したがって、どんなにRubyの機能が気に入ったとしても、実行時の効率性が必要なのであれば、C++を使い続けた方がいいでしょう。

 C++とRubyの重要な違いを理解したところで、それぞれの言語で実装された、小さいながらも完全なサンプルアプリケーションを見てみることにしましょう。このサンプルアプリケーションでは、指定ディレクトリ内の一連のファイルにおける各ワードの出現総数を計算し、出現ワード数のまとめを示すXMLファイルを生成して出力します。C++での実装をリスト、Rubyでの実装をリスト2に示します。サンプルコードのダウンロード用ファイルもご利用ください。

リスト1 C++での実装
// for directory manipulation
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>

// streams and strings
#include <iostream>
#include <fstream>
#include <string>

// STL collections
#include <map>
#include <set>

struct my_compare {
  bool operator() (const std::pair<std::string, int> &f1, 
                   const std::pair<std::string, int> &f2) {
    return f1.second < f2.second;
  }
};

struct word_count {
  std::string word; 
  int total_count; 
  typedef std::multiset< std::pair<std::string, int>, my_compare > 
          file_set_t;

  word_count(std::string _word) : word(_word), total_count(0) {}

  virtual void add(std::string filename) {
    total_count += 1;
  }

  virtual file_set_t file_occurrences() {
     return file_set_t();
  }
};

bool operator< (const std::pair<std::string, word_count *> &wc1, 
                const std::pair<std::string, word_count *> &wc2) {
  return wc1.second->total_count < wc2.second->total_count;
}

bool operator< (const word_count &wc1, const word_count &wc2) {
  return wc1.total_count < wc2.total_count;
}

struct word_and_file_count : public word_count {
  std::map<std::string,int> file_count;

  word_and_file_count(std::string _word) 
    : word_count(_word) {}

  void add(std::string filename) {
    if (file_count.find(filename) == file_count.end()) 
      file_count[filename] = 0;
    file_count[filename] += 1;
    total_count += 1;
  }

  word_count::file_set_t file_occurrences() {
     return word_count::file_set_t ( file_count.begin(),
                                     file_count.end() );
  }
};

template <typename W>
class word_counter {
private:
  std::map<std::string, word_count *> word_counts;
  const std::string directory_name;

  void count_words_in_file(const std::string &filename) {
    int i = 0; 
    std::ifstream file(filename.c_str());

    if ( file.is_open() ) {
      while (file.good()) {
        std::string line;
        getline(file,line);
        char c = line[i=0];
        while ( c != '\0' ) {
          std::string buffer;
          while ( c != '\0' && !isalpha(c) ) {
            c = line[++i];
          } 
          while ( c != '\0' && isalpha(c) ) {
            buffer += c;
            c = line[++i];
          }
          if (buffer.length()) { 
            if (word_counts.find(buffer) == word_counts.end()) 
              word_counts[buffer] = new W(buffer); 
            word_counts[buffer]->add(filename);
          }
        }
      }
    }
  }

public:
  word_counter(const std::string &_directory_name) 
       : directory_name(_directory_name) {}

  void count_words() { 
    char *cwd = getcwd(NULL,0);

    if (chdir(directory_name.c_str()))  {
       std::cerr << "Could not open directory" << std::endl;
       exit(1);
    }

    DIR *d = opendir(".");
    if (!d) {
       std::cerr << "Could not open directory" << std::endl;
       exit(1);
    }

    while (struct dirent *e = readdir(d)) {
      std::string filename = e->d_name;
      count_words_in_file(filename);
    }
    chdir(cwd);
    delete cwd;
  }

  void dump_results() {
    typedef std::multiset< std::pair< std::string, word_count * > > 
            wc_set_t;
    std::cout << "<counts>" << std::endl;
    wc_set_t wc_set(word_counts.begin(), word_counts.end() );
    for (wc_set_t::const_reverse_iterator it = wc_set.rbegin(); 
         it != wc_set.rend(); it++) {
      std::cout << "<word occurences=\"" << it->second->total_count 
                << "\">" << std::endl << it->second->word << std::endl;
      word_count::file_set_t file_set = it->second->file_occurrences(); 
      for (word_count::file_set_t::const_reverse_iterator 
             fit = file_set.rbegin(); fit != file_set.rend(); fit++) {
        std::cout << "<file occurences=\"" << fit->second << "\">" 
                  << fit->first <<  "</file>" << std::endl;
      }
      std::cout << "</word>" << std::endl;
      delete it->second;
    } 
    std::cout << "</counts>" << std::endl;
  }

  void run() {
    count_words();
    dump_results(); 
  }
};


int main(int argc, char *argv[]) {
  char *dir = argv[1];

  if (!strcmp(argv[1],"--no-file-info")) {
    word_counter<word_count>(argv[2]).run();
  } else {
    word_counter<word_and_file_count>(argv[1]).run();
  }
  return 0;
}

会員登録無料すると、続きをお読みいただけます

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

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

メールバックナンバー

次のページ
Rubyでの実装

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

  • X ポスト
  • このエントリーをはてなブックマークに追加
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

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

Michael Voss(Michael Voss)

Intel社のSenior Staff Software Engineer。2001年にPurdue大学からElectrical Engineering博士号を授与された。現在、IntelのThreading LabとToronto大学の非常勤講師を掛け持つ。平行プログラミングとコンパイラの最適化に...

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

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

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/1438 2007/06/28 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング