[c++] malloc したメモリを初期化する

この記事は、IT エンジニア向けです。

滅多に使わないので忘れるから、個人メモ。

c 言語ではメモリを確保する時に malloc を使う。
c++ では、同様に malloc を使う事も出来るが、普通は new を使う。

malloc はメモリを確保するだけだが、new はメモリ確保の後、確保したメモリの初期化まで行ってくれるからだ。

では問題。
c++ で、あえてメモリ確保に malloc を使用した場合、どうやって初期化すればよいか?

一般的に、メモリ確保処理は負荷が高い。
なので、c や c++ では一度に大量のメモリ確保を行う事がある。
インスタンスを 100 個作成する時、100 回メモリ確保をするより、1 回で100 個分のメモリ確保をした方がパフォーマンス的には良いのだ。

ただし、この時に new を使えない事が多々ある。
new でも複数インスタンスのメモリを一度に確保する事は可能なのだが、この場合コンストラクタに渡す引数がややこしい。
「引数無しのコンストラクタで初期化しておいて、後で各種設定を行う」で済む場合は良いのだが、そうとは限らない。

こんな場合は、初期化を行わない malloc の方が都合が良かったりする。
そうすれば、malloc でメモリ確保だけをしておいて、実際に使う直前にコンストラクタを呼び、初期化すれば良いのだから。

というわけで、malloc で確保したメモリに後からコンストラクタを走らせる方法のメモ。


#include <cstdlib>
#include <iostream>
#include <new>

using namespace std;

class Foo {
public:
  Foo(const char *msg) : msg_(msg) {}

  void hello() { cout << msg_ << endl; }

  ~Foo() {
    cout << "~";
    hello();
  }

private:
  const char *msg_;
};

void new_foo() {

  auto ptr = new Foo("new");
  ptr->hello();
  delete (ptr);
}

void malloc_foo() {

  auto ptr = malloc(sizeof(Foo));
  if (!ptr) {
    auto handler = get_new_handler();
    if (!handler)
      throw bad_alloc();
    else
      handler();
  }

  new (ptr) Foo("malloc");
  static_cast<Foo *>(ptr)->hello();
  static_cast<Foo *>(ptr)->~Foo();

  free(ptr);
}

int main() {

  new_foo();

  malloc_foo();

  return 0;
}

上記において、new_foo と malloc_foo は、ほぼ同様の働きをする。

new_foo は普通に new を使う方法だ。
new Foo ("new")で Foo クラスのインスタンスのメモリ確保、初期化を行い、メソッド hello を呼び出し、delete でメモリを解放している。

malloc_foo は、あえて malloc を使う方法。
最初にエラー処理以外の部分を見てみよう。

auto ptr = malloc(sizeof(Foo))で Foo に必要なサイズのメモリを確保する。
その後、new (ptr) Foo("malloc")とすると、ptr に確保されたメモリ上で初期化を走らせる。
この時、コンストラクタには “malloc” という const char * の引数を渡している。

その後 new_foo と同様にメソッド hello を呼び出す。

最後にメモリ解放をするのだが、malloc で確保したメモリは delete ではなく free で解放する必要がある。
free でメモリを解放する場合は明示的にデストラクタを呼ぶ必要があるので注意だ。

ついでなのでエラー処理についてもちょっと書いておく。
new にしろ malloc にしろ、メモリ確保は必ず成功するとは限らない。エラーが発生する可能性がある。

new の場合、デフォルトでは失敗時に bad_alloc クラスの例外が投げられる。
ただし、この処理は set_new_handler という関数で変更可能だ。
関数 new_foo では、この挙動に任せており特にエラー処理はしていない。

malloc の場合、失敗時は必ず null pointer が返される。
malloc_foo では、失敗時の挙動を new と同じになるようにしている。

つまり、返り値が null pointer の場合、まず set_new_handler で new のエラー処理が変更されているか確認する。
もし変更されていなければ、new のデフォルト動作である bad_alloc クラスの例外を投げる。
変更されている場合は、その関数を呼び出す。

以上、完全な俺メモでした。

結局、MVC とは何なのか?

この記事は IT エンジニア向けです

もはや 2 周くらい回って、そろそろ「ダサい」という人も出てきそうな MVC という言葉。
まあ、技術は日々進歩するわけだし、色々な意見があるだろう。
俺自身、MVC を使う事を推奨するつもりは毛頭ない
(非推奨という分けでも無いが)

でも、少なくとも MVC は一時代を築いた事があり、現在でも無視できない考え方だ。

何で MVC という考え方が生まれたのか?
その根本思想は何なのか?

個人的には MVC は構造化プログラミングの一つの良い例であり、GUI 以外にも色々と応用が利く考え方だと思っている。

実際、俺は今、業務で書いているプログラムの全体設計に MVC を参考にした。
GUI ではないので、当然 MVC の出番はない。
でも、俺の作ったプログラムには models というディレクトリが存在する

なので、今回は MVC についての俺なりの理解をザックリと書いてみる。
なお、個人の意見、解釈が満載なので、ご了承ください。
(と、予防線を張っておく)

さて、まず最初に MVC のそれぞれの単語について、簡単に考えてみよう。

View とは何だろうか?

View には「景色」「外見」などの意味がある。
その名の通り、View とは人間への見た目を司る部分だ。
Rails だったら、template 部分にあたるだろう。

次に、Controller とは何だろうか?

Controller とは「何かを制御する物」という意味だ。
では、MVC の Controller は「何を」制御するのだろうか?
そして、MVC において Controller は何をするのだろう?

最後に、Model とは何だろうか?

そもそも、Model という言葉の意味は何だろう?
「人体模型」、「ファッションモデル」
これらは全て Model な分けだが、本来、どういう意味だったのだろう?
一体全体、MVC の Model とは何なのだろう?

View は良いのだが、Controller と Model は直観的とは言い難い。
少なくとも、俺が初めて MVC (Rails) を学んだ時は、良く分からなかった。

ただ、今では View 以外の部分を Controller と Model に分けた事が MVC の凄さの源だと思っている。
なので、それぞれを簡単に紹介していく。

最初に、Model という言葉の意味からだ。

俺は、「A の Model」とは、
「A の重要な、注目している特徴をと同じ特徴持っている物」
という意味だと思っている。

多くは、A 自身を直接扱うのが困難な時に、代替として使うだろう。

「人体模型」は人体と同じ「臓器の形、大きさ、場所」等の特徴を持っている。
人体の臓器の勉強をする際に本物の人体を使うのが難しいので、
同じ特徴を持つ人体模型を使うのだ。

同様に、「ファッションモデル」は、その衣装を着る人と同じ
「性別、年齢」等の特徴を持っているのだろう。

では、プログラムにおける Model とはどういう意味だろう?

これは、「そのアプリケーションの特徴を持つ物」という意味だ。

例えば Users Model では

  1. 各ユーザーは email address を 1 個持つ
    この email address は全体で重複しない
  2. 各ユーザーはニックネームを持つ。
    このニックネームは登録時に作成され、以後変更は出来ない

等、アプリケーションのユーザーに関する特徴を実装している事だろう。

さらに、MVC の Model には 1 個、大きな制約がある。

それは、
「アプリケーションの同じ特徴を、複数の Model に記載してはいけない」
という事だ。

例えば、「各ユーザーは email address を 1 個持つ」というアプリケーションの特徴を Users Model に書いた場合、
「MailAddresses Model」に同じ特徴を書いてはいけない。

これを許可してしまうと、

  1. MailAddresses Model と Users Model で結果が変わる
  2. MailAddress Model を使うと、Users Model の「各ユーザーはニックネームを持つ」という特徴が消えてしまう

等のバグが生まれる可能性が増えてしまう。

この制限を加えるとで、同じ処理を行うために必要な Model の組み合わせを 1 通りに限定し、プログラムの見通しを良くしている。

「重複を許さない」という意味では DRY (Don’t Repeat Yourself) と似ているかもしれない。

でも、通常 DRY が「コピペしない、同じ処理を 2 箇所に書かない」だけだが、Model の制限は「異なる処理であっても、アプリケーションの同一の特徴に関わる物は異なる Model に書いてはいけない」という意味で、より制限が強いと言える。

要するに、異なる処理でも関連していれば 1 個の Model にまとめる必要が出てきたりするわけだ。

一方、Model のこの制限には、悪い事もある。
大きな Model を作ろうとすると、他の Model と特徴が被ってしまう事が多くなる。
必然的に、各 Model は小さくなるだろう。

Model が小さく、疎結合に分かれているのは良い事だ。
でも、それをまとめる大きな Model が作れないのは嬉しくない。
1 個のアクションで多くの Model を操作する必要が出てくるからだ。

ちょっと Users の事は忘れて、メモ帳や Word のようなエディタを開発する事を考えてみよう。

このエディタで「終了」ボタンが押された時のフローはどうなるだろう?
例えば、こんな風になるだろう。

  1. 現在開いているファイルの最新状態が保存されているか確認
  2. もし、最新状態が保存されていないならば、ポップアップを出してユーザーに確認
  3. ユーザーが「保存する」を選択したら、保存処理を行う
  4. プログラムを終了する

さて、この一連の処理を全て Terminate Model に記載するべきだろうか?
そうすれば、View からはその関数を呼び出すだけで済む。

(補足:Rails では View から Model を呼び出せないが、旧来の MVC では許される)

いや、それは現実的ではない。

最低でも、保存処理は Terminate Model から分けるべきだろう。
なぜなら、保存処理を Terminate Model に書くと、保存に関する特徴のいくつかは Terminate Model に紐づいてしまう。
(例えば、「デフォルトの拡張子は “.txt” にする」など)
すると、他の Model に保存処理を書けなくなってしまう。

「終了せずにデータの保存だけする」という場合に Terminate Model を呼び出すのは、あまりにも筋が悪い。
全ての処理を Terminate Model に書くことはあきらめよう。

では、if 文のネストと適切な Model の呼び出しを全て View に書くか?
それも良くない。

終了ボタンが複数個所にある場合、全ての場所にコピペするのだろうか?
また、ボタン毎にこれだけの処理を記載していたら View が肥大化してしまう。

そこで、Controller の出番だ。

Controller は一連の処理で必要な Model の呼び出しと、その制御フローを記載する。
上記の例では、Terminate Controller を作って、その中で if 文や各 Model の呼び出しを行えばよい。

View からは Terminate Controller だけを呼び出せば良い。
Controller が制御するのは、Model だったのだ。

誤解を恐れずに言うのであれば、Controller とは「『同じ特徴を複数の Model に記載してはいけない』という制限を取り除いた Model」という表現も間違ってはいない。

ただ、Model の制限は、プログラムを整理してより良くするために取り入れたもの。

「Controller は制限が無い、Model のスーパーセット」
というより、
「Model は自動整理機能つき。どうしても Model に書けない時だけ Controller に逃げる。ただし、その場合はスパゲッティにならぬよう自分で気を付ける必要がある」

と考えた方が良いだろう。

必然的に Controller からは複雑なロジックは減り、Model 呼び出しの為の簡単なマクロのような物になるはずだ。

「ロジックを Controller から Model に移せ」という格言にも通じる。

Model とはアプリケーション固有のロジックを記載したライブラリ
Controller とは Model をユーザーフレンドリーにするためのラッパー、ショートカット(ユーザーとは View を書く人)

と考えても良いだろう。

(アプリケーション固有ではないロジックは、Model ではなく汎用ライブラリとしてパッケージ化し、他のアプリでも共有しよう。)

話が長くなったので一旦、話を整理しよう。

MVC において、

Model とはアプリケーションの特徴(ロジック)を重複なく記述した部分

View とは GUI の見た目に関わる部分

Controller とは、Model を呼び出す制御 (条件分岐、ループなど) をする部分

となる。

今回の記事とは関係ないのだが、誤解を生むと嫌なので一応補足しておく

Controller は Model 「だけ」を呼び出す物では無い。
Controller から別の Controller を呼び出す事は超 OK。

Model が別の Model を呼び出す(又は、has-a の形で内包する)のは、ライブラリやフレームワークの思想に合わせよう。

これを許すと、実質的に一つの特徴を複数の Model が共有する事になる。
つまり、Model 同士が密結合になる。
個人的には好きではない。
だが、一般的には許される事が多いようだ。
フレームワークの思想に一人で反逆しても意味が有る事は少ない。
必要に応じて素直に従おう。

ところで、Rails のような Web アプリでは Model というと RDB へのアクセスを思い浮かべる人も多いだろう。

これは、「アプリケーションの特徴は、RDB のテーブル構造だけで記載出来る事も多い」という事に気が付いた DHH (Rails を作った人) が、フレームワークに専用の仕組みを作った事に由来する。

俺はコンピューターの歴史に詳しいわけではないが、
GUI を作るうえで「View とそれ以外の部分に分ける」
という考え方は、MVC 以前から存在していたらしい。

MVC の発明とは、View 以外の部分をさらに Model と Controller に分けた事。
Rails の発明とは Web アプリを作る際に MVC から Model の考えを拝借した事、
および Model 機能の多くを RDB のテーブル設計で補う考えを
フレームワークに明示的に取り入れた事。

そんな風に思っている。

さて、ここまでも個人的な解釈が満載なのだが、ここから下は超個人的な意見である。
注意してほしい。

ここまで MVC の Model と Controller について長く語ってきた。
この考え方は GUI にのみ通じる物だろうか?

そんな事は無い。
プログラムには多かれ少なかれロジックは存在する。
ならば、ロジックを Model と Controller に分けるという考え方は
ロジックの存在する(つまり全ての)プログラムで応用可能だ。

さらに言うと、Rails の「全てをプログラムに頼らず、RDB のテーブル設計で解決する」という発想も個人的には大好きだ。

より汎用的に言えば、RDB に限らず
「アプリケーションの特徴の一部をミドルウェアやサーバー構成、ネットワークに反映させる」
という考えをすると面白い。

例えば、「冗長化のために Web サーバーを複数台構築する」という考え方は間違っていないが、少し物足りない。

「このアプリケーションは、複数人で同時に使える特徴を持っているべき。ユーザーの使用感は他のユーザーの使用状況に関係ないという特徴を持っているべき。ユーザーのリクエストが何かの拍子に失敗しても、再実行すれば成功するべき」
「Web サーバーが複数台存在して、各 Web サーバーが勝手にリクエストを処理するというアーキテクチャは、この特徴とマッチしている」

と考えられないだろうか?

つまり、全体のアーキテクチャを考える時、

「仕様や処理」を軸にするのではなく、

「アプリケーションが持つべき特徴は何だろう?」
「その特徴にマッチする構成は何だろう?」

という風に考えてみるのだ。

すると、「頭の中で描いた処理がそもそも良くなかった」と気付く事もあるだろう。
「仕様がおかしいのではないか?」と疑問がわくかもしれない。

また、個々の処理はプログラムの改修等で簡単に変わってしまう。
根本方針をちゃんと考えたならば、「アプリケーションの特徴」は個々の実装よりも寿命が長くなるだろう。
アーキテクチャというプログラムより寿命の長い物を考える時に、、同様にプログラムより寿命の長い「特徴」を参考にできれば幸せになれるのではないか?

「言葉遊びに過ぎない。結局、考える事は同じだよ」と言う人もいるかもしれない。
確かに、それは本当。
でも、アプリケーションの特徴は要件と直結している。
要するに、「仕様」よりも「特徴」という言葉の方が、より抽象化された上位概念なのだ。

作業を進めていくと、どうしても「木を見て森を見ず」の状態になりやすい。
すると、そもそも論で論破されるような、つまらない過ちを犯してしまう。

そんな事を防ぐために、時には必要以上に上位レイヤーで考えるのも良いものだ。
言葉遊びと笑われようが、これは良いきっかけになる。

以上。
最後は少し乱暴というか、個人的な意見を述べ過ぎてしまったが、MVC の概要でした。

なんで 0.99999… = 1 なの?

昔、疑問に思っていた事を、ふと思い出した

0.99999… = 1

これは本当だろうか?
正しい気もした、間違っているきもした。

  1. 1 / 3 = 0.33333…
  2. 0.33333… x 3 = 0.99999…
  3. 1 / 3 x 3 = 1
  4. よって、0.99999… = 1 は正しい
  1. 0.9 < 1
  2. 0.99 < 1
  3. 0.999 < 1
  4. このように、0.9 の後にどれだけ 9 を付け足しても 1 より小さい
  5. よって、0.99999… < 1
  6. よって、0.99999… = 1 は間違い

どちらの考え方も一見正しいように見えるが、正反対の結論になってしまった。

実は、この議論を始めるために最初に確認しなくてはいけない事がある。
0.99999… とは何だう?

0.9 の後に 9 を無限個、続けた数字?
「無限」って整数だったの?
整数って事は、偶数か奇数のどちらかだ。
「無限」って偶数?奇数?

「無限」について数学的に正しく扱う事は簡単ではない。
だが、ここが上の議論で一番重要な点だ。
0.33333… や 0.99999… を正しく定義できれば、このパラドックスは理解できる。

「無限」という言葉を使うと難しくなるので、その言葉を使わずに 0.99999… を定義してみよう
以下のような数列 an を考える。

a1 = 0.9
a2 = 0.99
a3 = 0.999

ちなみに、数学的に厳密に書くと

a1 = 0.9
ak+1 = ak + (9/10k+1)

となる。
(まあ、表現が難しくなっただけで今回の記事には関係無いが)

さて、この数列 an は以下の 2 個の特徴をもつ。

i) どんな自然数 n においても、an < 10
ii) どんな自然数 n においても、an < an+1

i) と ii) を真面目に証明するとこの記事が長くなりすぎるので、ここは「当たり前」で許してほしい。

では、i) と ii) の条件を満たす数列のグラフはどんな形になるだろう?
(今は an の詳しい事は一回忘れて、「i) と ii) の条件を満たす数列」のグラフを考えよう。)
例えばこんな形になるのではないか?

上図を見ると直観的に分かるかもしれないが、an は「n を大きくするとある数に近づく」という性質を持っている。

なぜなら
ii) どんな自然数 n においても、an < an+1
より、an は、n を大きくすると
「際限なく大きくなる」
「上限となる、ある数に近づく」
のどちらかである。

そして、「際限なく大きくなる」は
i) どんな自然数 n においても、an < 10
と明らかに矛盾する。

この「上限となる、ある数 x」を先ほどの図に加えるとこのようになる。

では、この x について厳密な定義をしてみよう。
(「n を大きくすると近づく数」という表現は数学的には曖昧すぎる)

先ほど an について
i) どんな自然数 n においても、an < 10
と書いた。
当たり前だが、この条件はもっと厳しくする事ができる。
例えば、

i’) どんな自然数 n においても、an < 5
i”) どんな自然数 n においても、an < 3

これはどちらも正しい。

この条件を一番厳しくした時の値で x を定義する。
i), i’), i”) では 10, 5, 3 という数字を使ったが、もっと小さい数を使う事も出来る。
この使用可能な数の中で、最小値を x とするのだ。
正確に書くと以下のようになる。

a)
どんな自然数 n においても、an < k を満たす数 k は 2 個以上存在する。
x はそのような k の中の最小値

別の言い方をすると、こんな風になるかもしれない。

b)
どんな自然数 n においても、an < x。
ただし、y < x を満たす全ての数 y において、 y < an となる n をが 1 個以上存在する

x の定義は上記の a), b) どちらでもよい。

数学的にはいい加減だが少しだけ直観的な表現にすると、

c)
x とは 0.9 の後に 9 を多く続けた数より、少しだけ大きい数
(「多く」とは、100万でも 10億でも良い)

とも言えるだろう。
「少しだけ大きい」という部分がポイントだ。

そして、この数 x を 0.99999… と名付けよう。

すると、「0.99999… = 1」とは、

a) の表現を用いると
0.9 の後に 9 をいくつ続けた数よりも大きい数は 2 個以上存在する。
そのような数の最小値は 1 である

b) の表現を用いると
0.9 の後に 9 をいくつ続けても 1 より小さい。
1 より小さい全ての数 y について、0.9 の後に 9 をいくつか続けると y より大きくなる事がある

c) の表現を用いると
0.9 の後に 9 を多く続けた数より、少しだけ大きい数は 1 である

という事になる。

どうだろう。
「”0.9 の後に 9 を無限個繋げた数” = 1」
という表現とは全然違う印象を受けるのではないか?
そして、この表現ならば直観的にも簡単に納得できるだろう。

では、最初のパラドックスに戻ってみよう。

長くなるので、以下では c) の表現のみを用いてみる

  1. 1 / 3 = 0.33333…
    1 / 3 = “0.3 の後に 3 を多く続けた数より、少しだけ大きい数”
  2. 0.33333… x 3 = 0.99999…
    “0.3 の後に 3 を多く続けた数より少し大きい数” x 3
    = “0.9 の後に 9 を多く続けた数より少し大きい数”
  3. 1 / 3 x 3 = 1
  4. よって、0.99999… = 1 は正しい
    “0.9 の後に 9 を多く続けた数より少し大きい数” = 1 は正しい。

これは全て正しい。

1 / 3 = "0.3 の後に 3 を多く続けた数より、少しだけ大きい数"

ここが直観に反するかもしれないが、実際には正しい。
(数学的に厳密な証明は、今回は控える)

  1. 0.9 < 1
  2. 0.99 < 1
  3. 0.999 < 1
  4. このように、0.9 の後にどれだけ 9 を付け足しても 1 より小さい
  5. よって、0.99999… < 1
    “0.9 の後に 9 を多く続けた数より少し大きい数” < 1)
  6. よって、0.99999… = 1 は間違い
    “0.9 の後に 9 を多く続けた数より少し大きい数” = 1 は間違い

これは間違っている。

0.9 の後にどれだけ 9 を付け足しても 1 より小さい
"0.9 の後に 9 を多く続けた数より少し大きい数" < 1

この間に議論の飛躍がある。
ここで間違えているのだ。

この疑問を始めて感じたのは、小学生の時だったと思う。
その際、周りの大人たちに聞いたが納得のいく解答は得られなかった。
(今にして思うと、大人にも良く分からなかったのかもしれない)

小学生だったころの自分にも分かるような説明を考えてみたが、どうだろうか。