Max OS X Lionに上げたらEclipseでJavaがビルドできなくなった

MacをLionにアップデートしたら、EclipseJavaコンパイルできなくなっていました。Eclipseのバージョンは3.6(Helios)です。
Problemsタブには、次のようなエラーが出ていました。

The container 'JRE System Library [JavaSE-1.6]' references non existing library '/System/Library/Frameworks/JavaVM.framework/Frameworks/JavaRuntimeSupport.framework/Resources/Java/JavaRuntimeSupport.jar'


Eclipseの環境設定で、次のところを直したら動くようになりました。

Java -> Installed JREs」 でどれにもチェックが付いていなかったので付ける


Java -> Installed JREs -> Execution Environment」 で「Compatible JREs」のどれにもチェックが付いていなかったので付ける

中国GTUG第11回勉強会

12/3に開催された第11回中国GTUG勉強会にて、「DevQuiz完全制覇までの道のり」というタイトルで話させてもらいました。
発表資料:http://tomerun.info/presen/ChugokuGTUG11/presen.html


スライドパズルの最後の方手動でやったり分野別パズル全部やってなかったりなので、「完全制覇」と大きく出るのはちょっとはばかられますがそのへんはまあマーケティング(?)上の理由です。
数ヶ月前の記憶を頼りに書いた部分がかなりあるので多少間違ったところがあるかも…
資料の量が時間通りになるように気にして作るまでできなかったけど、結果的にはちょうど良かったです。やっぱりスライドは1枚1分が目安か


こういう勉強会への参加というのはやっぱり発表してこそだなよなあ、というのを再認識しました。

基底クラスのデストラクタをvirtualにしなくてもメモリリークしない場合

こんな感じのコードを目にしました。

#include <vector>

struct Base {
  ~Base(){} // non-virtual
  virtual void doSomething() = 0;
};

struct Derived1 : public Base {
  virtual void doSomething(){ ++x; }
  int x;
};

struct Derived2 : public Base {
  virtual void doSomething(){ x ^= y, y ^= x, x ^= y; }
  int x;
  int y;
};

int main(){
  std::vector<Base*> vec;
  for (int i = 0; i < 100000; ++i) {
    vec.push_back(new Derived1());
    vec.push_back(new Derived2());
  }
  for (Base* base : vec) {
    delete base;
  }
  return 0;
}

「おおっとーBaseのデストラクタがvirtualになってないぞーサブクラスの拡張部分が解放されない!」と思ったけど、これ実際に動かしてみるとメモリリークしません(VC2005とg++4.6で確認)。
デバッガ使ってみると、確かにDerivedのデストラクタは呼ばれていないのだけど…。


推測ですが、new Derived1()したときに返るポインタが内部的には malloc(sizeof(Derived1)) によって取得されたもので、それに対してdeleteするとfree()が呼ばれるようになっている。つまり結局はmallocしたものをfreeしてるというだけなので解放できてしまっているんじゃないかと。

newやdeleteのデフォルトの実装がそうなるよう決められているわけではないと思うので、きっと環境依存の振る舞いでしょうが…


もちろん、次のようにDerivedのメンバに要解放リソースを確保していたらリークします。

#include <vector>

struct Base {
  ~Base(){} // non-virtual
  virtual void doSomething() = 0;
};

struct Derived1 : public Base {
  Derived1() { x = new int(1); }
  virtual void doSomething(){ ++x; }
  int* x;
};

関数テンプレートのオーバーロードにはまる

動作確認環境:VC20052008、VC2010、g++4.5

関数テンプレートの特殊化

任意の型のオブジェクトを出力する次のような関数テンプレートを書くことがありました。
元々が文字列だった場合だけ特別扱いしたい事情があって、テンプレートの特殊化をしています。

// (A)
template<class T> void output(T val){
  std::cout << val << std::endl;
}

// (B)
template<> void output(const std::string& val) {
  // 文字列の場合は装飾して表示する
  std::cout << "***" << val << "***" << std::endl;
}

// (C)
template<> void output(const char* val) {
  // 文字列の場合は装飾して表示する
  std::cout << "***" << val << "***" << std::endl;
}

int main(){
  const char* szStr = "Fizz";
  output(szStr);                     // (C)
  char ary[] = {'B', 'u', 'z', 'z', 0};
  char* szStr2 = ary;
  output(szStr2);                    // (A)
  std::string str("foo");
  output(str);                       // (A)
  const std::string& strRef = str;
  output(strRef);                    // これも(A)
  return 0;
}

ただ、これだとうまくいきません。const char* 以外を渡した場合、特殊化バージョンではなくベーステンプレートのほうが呼ばれます。
推測ですが、たとえばstringの場合だと、output()に渡したときには参照ではないstd::string型で渡されていて、ベーステンプレートをstd::stringでインスタンス化したものは完全に型が一致するが、一方特殊化バージョンのほうはconst化と参照へのバインドを行わないといけないので型の一致度が低いので使われない、という事情でしょうか。


言語仕様(C++0x規格書ドラフト:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3092.pdf)では「14.8.2 Template argument deduction」あたりに書いてありそうですが、これを追うところまではできませんでした。

関数テンプレートとそのオーバーロード

一般的に、関数テンプレートは特殊化するよりもオーバーロードを使ったほうが良いので(参照:http://www.gotw.ca/publications/mill17.htm)、特殊化をオーバーロードに置き換えてみました。

// (A)
template<class T> void output(T val){
  std::cout << val << std::endl;
}

// (D)
void output(const std::string& val) {
  std::cout << "***" << val << "***" << std::endl;
}

// (E)
void output(const char* val) {
  std::cout << "***" << val << "***" << std::endl;
}

int main(){
  const char* szStr = "Fizz";
  output(szStr);                     // (E)
  char ary[] = {'B', 'u', 'z', 'z', 0};
  char* szStr2 = ary;
  output(szStr2);                    // (A)!!
  std::string str("foo");
  output(str);                       // (D)
  const std::string& strRef = str;
  output(strRef);                    // (D)
  return 0;
}

これだと、std::stringを渡した場合は関数テンプレートではなくてオーバーロードした非テンプレートの関数が呼ばれます。
そもそもどうして関数テンプレートの特殊化ではなく非テンプレート関数によるオーバーロードのほうを使うべきかというと、関数テンプレートよりも非テンプレート関数のほうが引数の型が合っていれば優先して選ばれるので、特定の型の場合だけ別の実装を使いたいという意図通りの結果になるからですし。


しかし、char* を渡した場合にはconst char*を引数に取るオーバーロードが使われずに関数テンプレートのほうが選ばれてしまうのです。
std::stringでは非constのオブジェクトを渡した場合にもconst std::stringを引数に取るオーバーロードが選ばれるのに。
これがなぜなのか分からなくて、困りました。ポインタかどうかあたりで違いがあるのでしょうか。


とりあえず、非constのchar*を取るオーバーロードも追加して一応意図通り動くようにしましたが、気持ち悪い…。

void output(char* val) {
  output(static_cast<const char*>(val));
}


規格を頑張って読むしかないのかね。


おまけ:g++でtypeinfoから型の名前を得る

ベーステンプレートが実際にどの型でインスタンス化されたかを調べようとtypeinfoを使おうとしたら、g++のtypeinfo::name()はhuman-readableではないマングリングされた名前を返してくることを知りました。
次のように、abi::__cxa_demangle()関数(http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01070_source.html#l00145)を使うとdemangleできます。

#include <iostream>
#include <typeinfo>
#include <cstdlib>
#include <cxxabi.h>

template<class T> void output(T val){
  int status = 0;
  char* name = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status);
  std::cout << name << std::endl;
  std::free(name);

  std::cout << val << std::endl;
}

int main(){
  const char* szStr = "Fizz";
  output(szStr);
  char ary[] = {'B', 'u', 'z', 'z', 0};
  char* szStr2 = ary;
  output(szStr2);
  std::string str("foo");
  output(str);
  const std::string& strRef = str;
  output(strRef);
  return 0;
}

出力:

char const*
Fizz
char*
Buzz
std::string
foo
std::string
foo

Windows上のVMWareにDebianを入れる

今年のICFP Programming Contestはプログラム実行環境がDebianだそうなので、Windows7(64bit)にVMWareを入れてDebian6.0が動かせるようにした。
そのメモ。

Debianのディスクイメージを準備

http://www.debian.or.jp/using/ からDebian6.0の安定版ディスクイメージをダウンロードした。
CDとDVDがあってどう違うのかわからないけどDVDのほうがサイズがでかくてお得そう(?)なのでDVDのほうを選んだ。
ダウンロードには30分くらいかかった。
ダウンロードしたイメージはDVDに書きこんでおく。

VMWare Playerをインストール

http://www.vmware.com/go/get-player-jp からVMWare Playerをインストールする。
登録が必要なのでそのへんは適当に。
VMware Player (32 ビットおよび 64 ビット版 Windows 用)03/29/11 | 3.1.4」を選択した。
ダウンロードしたexeを実行してインストールする。インストール後には再起動が必要。

仮想マシンの作成

VMWare PlayerでDebianのディスクイメージを書き込んだDVDを指定して、仮想マシンを作成する。
VMWareがOSを自動検出できないと言われたので、自分でゲストOSを選択する。しかしDebian6.0は一覧にない。
よくわからないけどとりあえず「他のLinex 2.6.x カーネル 64ビット」を選んでみる。

あとは流れに沿ってだが、いくつか引っかかったところを記録する。



作成の途中でディスクのパーティショニングでは「ガイドーディスク全体を使いLVMをセットアップする」を選択


アーカイブミラーではftp.nara.wide.ad.jpを選択(なんか近そうだったので)

 
コンポーネントの選択ではデフォルトを選んでしまったが、ホストのWindowsや他マシンからログインして使う可能性を考えるとSSHサーバーにチェックを入れておくべきだったかも

Debian起動、設定

しばらく(30分くらい?)待つと、インストールが完了する。
起動してみると、やたらVMWareの画面が小さくてウィンドウの端をドラッグしてリサイズしようとしても広がらない。
Debianのほうで、システム-設定-モニタ から画面解像度を好みの値に設定してやるとそのサイズで表示されるようになった。

2011年頭所感

まず去年の目標評価を:

PA[120%]
Algorithm。TopCoderのレーティングで SRM+Marathon≧4200
→4395で達成。なぜか後半急に伸びた
PB[50%?]
Book。本を40冊読む。
→技術書だと頭から全部読んでいくのは効率が悪くて、必要なところや面白いところだけ拾うというのが多いので「何冊読んだ」というのは言いづらい
PD[??%]
何のつもりだったか忘れてしまった…
PL[12%]
Logging。家計簿と1ヶ月ごとの目標評価を付ける。
→やるだけだったのに見事に崩壊してしまった
PM[0%]
Marathon。フルマラソン3時間30分。
→また爪がはがれた+春先の体調不良でまったく走れず
PP[20%]
PRML。読破する。
→今のところ3章の途中まで
PR[0%]
Ruby。何か作る。
→成果なし
PS[100%]
Security。セキュリティスペシャリスト取る。
→取った。が思っていたよりもマネジメント寄りの内容で身についたスキルとしてはいまいち
PT[4%]
まだ秘密


そして今年やるつもりのこと:

  • PRMLを読み切り、機械学習の手法を利用したもの(単なるサンプル動作確認ではない、アプリケーションorサービス)を作って動かす
    • サーバー運用についてのノウハウを覚える
    • いまだSQL未経験なのでいいかげんDBに触る(ことができるような題材/実装方法を選ぶ)
    • 可視化手法を覚える
    • 良いテーマになりそうなアイデアの収集
  • 勉強会かセミナーか何かで1回は発表する
  • ICFPCにチーム組んで参加する(メンバー募集!!)
  • SRMMarathonCodeforcesでトリプル赤
  • 今年こそ家計簿付ける