コンストラクタの例外安全性とスマートポインタ

コンストラクタ内で例外を投げるべきではない、という主張がある。(今回は、デストラクタ内でという話ではない。念のため。)
例外を投げる可能性のある処理をコンストラクタから追い出すのが難しいケースなんて普通はそれほど無いので、基本的には素直にそうしておくとよい。

さて不幸にも実際にコンストラクタ内で例外が投げられると何が起こるのか。以下のコードを見るとわかるように、実は言語的にはちょっと賢いことをしている。

#include <iostream>
#include <memory>
using namespace std;

struct A {
  explicit A(const char* name): name_(name) {
    cout << "A: constructed: " << name_ << endl;
  }
  ~A() { cout << "A: destructed: " << name_ << endl; }
  const char* name_;
};

struct B {
  B() { throw "Boooom!!!"; cout << "B: constructed" << endl; }
  ~B() { cout << "B: destructed" << endl; }
};

struct X {
  X():
      a0_("direct"),
      a1_(new A("raw ptr")),
      a2_(new A("auto_ptr")),
      b_(new B),
      a3_(new A("auto_ptr never constructed")) {
    cout << "X: constructed" << endl;
  }
  ~X() { delete a1_; cout << "X: destructed" << endl; }

  A a0_;
  A* a1_;
  auto_ptr<A> a2_;
  auto_ptr<B> b_;
  auto_ptr<A> a3_;
};

int main() {
  try {
    X x;
    cout << "Construction completed" << endl;
  } catch (...) {
    cout << "Recovered" << endl;
  }
}

実行結果:

A: constructed: direct
A: constructed: raw ptr
A: constructed: auto_ptr
A: destructed: auto_ptr
A: destructed: direct
Recovered

コンストラクタはメンバ変数を宣言順に初期化し、最後に初期化ブロックを実行するのだが、途中で例外が起こると、デストラクタのコードブロックは実行されず、初期化が完了した変数だけが逆順にデストラクトされる。

つまり、初期化リストで new してデストラクタで明示的に delete を呼ぶようなコードではリークする可能性がある。しかしスマートポインタに突っ込んでおけば安心安全ぐっすり眠れてしあわせである。スマートポインタが使えない宗教の人は、初期化リストではなく、コンストラクタのコードブロック内で new と代入をするほうが C++ 的には正しい。

余談だが、あるクラスが "所有する" オブジェクトを直接メンバ変数として持つ代わりにポインタにしておくことのメリットはいくつかある。オブジェクトサイズが減るのでコピーのコストが下がると同時にローカル変数でもそのメンバ変数の領域がスタックではなくヒープに確保されるだとか、前方宣言だけあれば良いのでヘッダを include する際に依存関係を増やさずにすむだとか。dereference のオーバーヘッドとか普通は気にしない。

ファイル構成とか

とりあえず Hello World 的なものを書いた(というより Eclipse が自動生成したものを読んだり弄ったり)。

src の下にソースコード、 res の下に設定やデータ等の各種リソースファイルを配置。 res/layout/main.xmlソースコード中の R.layout.main という int のリソース ID に対応していて、R.java 自体は gen の下に自動生成される。なるほどなるほど。

Android ことはじめ

いっちょAndroidアプリでも作ってみようかと思ってこちらの本を読み始めた。

スマートにプログラミング Android入門編

スマートにプログラミング Android入門編

略語とかメモ。まぎらわしい。

"Android SDK and AVD Manager"

名前長いよ。もっと短い名前をビシッと決めてあげなよ。。

読んだ: プログラミングのための確率統計

プログラミングのための確率統計

プログラミングのための確率統計

前作 プログラミングのための線形代数 同様の軽妙な語り口で、確率変数は標本空間内の点を取る関数であるという定義がどんな意味をもつのかという根本的なところから、大数の法則は何がどう嬉しいのかだとか、多次元データにおける共分散行列の幾何的な見方などが大変分かりやすく説明されています。

また、3章から5章にかけて、扱う確率変数が離散値→連続値→ベクトル値と一般化していく中で期待値や分散といったおなじみの操作が拡張されていくのですが、数学的にテクニカルな部分も結構あります。そういった面倒な数式操作が全体の流れをざっくり理解する妨げになりがちですが、この本は解析学線形代数のフォローもそこそこ手厚いと思います。変数変換のインクの喩えなんかはなるほどーと思いました。

後半(第二部)はさらっと読み流すのが良いのでしょう。いろいろな応用の中で、確率をどう使って何が行われているのかということを、前半で学んだような視点で解説しています。

読んだ: 完全独習 統計学入門

完全独習 統計学入門

完全独習 統計学入門

Amazon で高評価だったので買ってみました。ふつうに良書だと思います。

特に以下の点が良いと思いました。

  • 前半で標準偏差の直感的な理解をしつこいほど強調していること
  • 「予言的中区間」という直感的にわかりやすい概念を導入し、それを逆から見たものが信頼区間だという説明

後半は正規分布の母平均と母分散の区間推定の手順を説明していて、母数が既知の場合から未知の場合へと段階的に進んでいくという一般的な構成なのですが、「分布が完全に分かっていて未知変数を1つ含む統計量を標本から計算し、95%信頼区間を得る」という画一的な手順を繰り返し行っていることがわかりやすく、ひとつひとつ確認しながら自分で推定を行うのに必要十分な理解ができるようになっていると思います。

ゴールに向かって最短距離で進む感じが良いですね(前半は株の話とか結構冗長な気もしますが)
分量が多くないので半日で読めます。まったくの初学者でも2週間もあればいけそう。

推定するのは母集団ではなく母集団の確率分布

ここ最近、統計を勉強しています。
統計学のメインテーマのひとつとして、有限個の観測値から母集団について推測をする、というのがあるわけですが、学ぶにつれてこの母集団というものに対するイメージが変わってきたのでそれについて書いてみます。

学びたてのうちは、たとえば選挙の開票みたいな例から入ったとして、この場合は「膨大な量の投票用紙に書かれた名前の集合」を母集団、「その中のごく一部」を標本としてはっきりと思い浮かべることができます。このような場合には、標本から母集団を推測することの意味が明確です。たとえその膨大な量というのが無限大だったとしても楽にイメージできるでしょう。

しかしこの母集団というのが厄介で、直接こいつらについて何かを推測しようとしても何をすればいいやらよく分かりません。そこで「母集団がある確率分布に従うと仮定すると、その確率分布はこれこれであるのがもっともらしい」という話へと持って行きます。推測する対象を母集団そのものから、母集団がしたがう確率分布に置き換えているわけです。

統計学はいろいろなツールを提供してくれますが、このような「推測対象の置き換え」を行っていることを意識しておかないと、検定・推定を行っていく過程で「あれ?自分はいったい何がしたいんだっけ?」というのがよく分からなくなってくることがあります。

上の選挙の例のように、母集団に対応するものが現実に存在している場合は、確率分布が求まった後、それを使って母集団を説明することがゴールです。標本という現実のデータからいったん確率分布というある意味で理想的な数学モデルを構築し、それを再び現実世界に適用するわけですから、仮定が100%正しいのでない限り、モデルと現実の母集団の間に多少のズレが生じます。

しかし母集団にあたるものが観念的なものである場合はむしろ、欲しいものは確率分布という数学モデルそのものの方であることが多いです。このような場合、母集団はそのモデルに完全にしたがうと考えればよく、あまり母集団というものを明示的に意識しません。そのモデルをそのまま使って何らかの分析を行えばよいのです。

何が言いたいかというとタイトルの通りで、統計によって操作する対象は母集団そのものではなく、あくまで背後にある数学モデルなのだ、というイメージを持つべきなんじゃないかな、と思ったのでした。

先の選挙の例でいうなら、たとえ実際にすべての投票用紙を集計したとしても、同じ分布に従うパラレルワールドの選挙とは少し結果がズレるでしょう。でも分布がわかればそのズレの範囲は予測可能です。「すべての投票用紙」という母集団がラスボスなんじゃなくて、「どんな分布に従って各候補者の名前が現れるか」のモデルこそが母集団を影から操る真のラスボスであり、こいつをつきとめることこそが統計の仕事。その成果を応用するのが人間の仕事です。