連載
» 2007年03月22日 00時00分 公開

Symbian OS開発の勘所(3):C++によるオブジェクト指向開発のメリット (3/3)

[大久保 潤 管理工学研究所,@IT MONOist]
前のページへ 1|2|3       

C++とSymbian OS

 C++はCをベースとして、そこにオブジェクト指向をサポートする機構を追加した言語です。ほかのオブジェクト指向言語と比べて、以下に示すような特徴があります。


1.Cの拡張なので、Cと同じコードを書くことも可能
だからC++に移行したくない人がいるという話がますます理解できないわけです。

2.極力コンパイル時に解決をしようとする
ポリモーフィズムを支える基礎となる仮想関数も、ビルド時に関係が決定されており、動的にメソッド探索が行われることはありません。

3.メモリロケータなど、実行環境に制約される部分は利用者が介入できるようになっている
実行環境に適したメモリ管理の方法を、言語の枠組みの中でうまく扱えるようになっています。

 2および3の特徴が、Symbian OSがターゲットとする環境には欠かせません。大規模開発のためにオブジェクト指向アプローチが必要だけれども、しかし性能を保証できる言語である必要もある。そのようなわけでC++が採用されたのだと思われます。

 では、C++は携帯、スマートホン向けのシステム記述言語における“銀の弾丸”なのでしょうか? ちょっと視点を変えて検討してみたいと思います。

※コラム:オブジェクト指向支援機能付き超高級アセンブラ
筆者自身、Symbian OSと出合う以前からC++を使い倒していて、C++のことは「オブジェクト指向支援機能付き超高級アセンブラ」という認識でいました(ちなみにCは「構造化支援機能付き高級アセンブラ」)。だからSymbian OSのアプローチを見たときに、大変に共感した記憶があります。


C++におけるメモリリーク

 C++では、クラスからオブジェクト(厳密にいうとクラスのインスタンス)を作成する方法は2つに大別できます。1つは、new演算子でオブジェクトをヒープ上に確保する方法。この場合、オブジェクトが不要になった際にdelete演算子で解放を行う必要があります。もう1つの方法は、別のメモリコンテキストの一部として領域を確保する方法です。自動変数として宣言し、スタック上に実体を確保する場合が該当します。

 C++におけるメモリリークとは、newで確保されたオブジェクトが何らかの理由によりdeleteされないことにより発生します。「じゃあ、メモリリークしないように開発者の皆さんは忘れずにdeleteを呼んでください、よろしく」という話で終わらせてしまえるかというと、もちろんそんなことはありません。

 C++では、ポインタの指している先がヒープなのかスタックなのかを知る一般的な方法がありません。これは結構深刻な問題です。いまポインタが指しているオブジェクトはdeleteで明示的に消す必要があるものなのか、それとも勝手に解放されるのでこちらで消すとまずいものなのか。この判断をプログラム上からできないことを意味します。

 オブジェクトの後始末に関する処理が1カ所に集約されている場合を想定してください。一般にC++における後始末は、「終了処理をせよ」という指示をオブジェクトに出す部分と、必要であればオブジェクト自体の消去を行う部分の2つからなっています。ヒープ上のオブジェクトに対してはdeleteが必須です。逆に、スタック上のオブジェクトに対してdeleteを発行すると、プログラムは異常終了することになります。

 あるクラスXのオブジェクトをヒープ上に取るかスタック上に取るかは、言語的には大した問題ではありません。しかし、交ぜて使うとこのように後始末処理などで混乱することになります。ポインタに属性がぶら下がっていて、deleteの要否が動的に判断できればよいのですが、C++には残念ながらそのような機能はありません。後始末を集約する目的は、例えばメモリリークがないことを保証するためなのですが、ここに至って本末が転倒してしまう可能性があることがお分かりいただけるでしょう。「本当にヒープにオブジェクトを取ってるんだよな? delete発行してもいいんだよな?」そんな疑念を解消する方法は、実はC++には備わっていないのです。

 ではほかの言語ではどのようにクラスのインスタンスを作り分けているのでしょうか。

 GC機能付きのOOPLでは、型を分別する物差しが古典的な言語とは異なっています。そのモノが置かれるメモリの種類によって分類をするわけで、これはかなり画期的な定義です。このアプローチは、まさにいま問題にしていることへの回答となり得る考え方です。

Symbian OSのアプローチ

 やっとSymbian OSにおけるC++の使い方にたどり着くことができました。実は、Symbian OSでもGC機能付きOOPLと同じく、クラスの種類をメモリの使い方で分けています。クラスを値型のインスタンスしか作らないものと、参照型のインスタンスしか作らないものに分けてしまえば、あるポインタがdeleteを必要とするのか否かは、クラスごとに一意に定まることになります。

 これは誰が何のまねをしたということではなくて、オブジェクト指向を計算機資源(ヒープとスタックという非対称なメモリ環境を持つ)の上にインプリメントすることをマジメに考えたら同じ結果になったということだと思います。そういうものを一般に「安定した概念」といいます。ただしSymbian OSはC++を採用しているため、言語とやりたいことの間にギャップが発生することになります。

 そこでSymbian OSでは、C++の言語仕様だけではカバーできない部分に関して、各種の規約(コンベンション)を導入することで解決を図っています。メモリの取り方も例外ではなく、以下のような規約が用意されています(注)。

※注:
これ以外にも、今後本連載の中でSymbian OSのさまざまな規約を取り上げていく予定です。


分類 特徴
Tクラス クラス名は「T」から始まる必要がある(「Type」のT)
・ 単純な型
・ スタック上またはクラス、構造体のフィールドにインラインに作ることができる
・ デストラクタを持ってはならない(デストラクタが必要となる構造はすでに「単純」ではない)
Cクラス クラス名は「C」から始まる必要がある(「Class」または「Compound」のC)
・ いくつかのクラスを要素に持つ複合的な型
・ new(ELeave)演算子(次回解説)でヒープ上に作らねばならない
・ CBaseの派生クラスである必要がある
表1 クラス分類

 ポインタの型名を見れば、インスタンスのメモリ種別が分かることになります。先に述べたようなポインタの読み分け問題は、Symbian OS環境では無縁となります。

 これ以外にもクラスの典型的な使われ方を表現するために、以下のようなクラス名に関する規約が存在します。

分類 特徴
Rクラス クラス名は「R」から始まる必要がある(「Resource」のR)
・ リソースを参照するクラス
・ リソースへのハンドルは十分小さいが、リソースの確保、解放という状態管理が存在するためTクラスと分別して考える必要がある
Mクラス クラス名は「M」から始まる必要がある(「Mixin」のM)
※Mixinは多分Symbolics社のFlavorsから
・ インターフェイスを定義するクラス
・ Javaでいうinterfaceとほぼ等価な機能を提供する
表2 クラス分類(続)

 GCこそありませんが、最新のOOPLで使われている概念がSymbian OS環境にも存在することが分かるでしょう。Symbian OSではこれらの概念を組み合わせて、携帯、スマートホン向けのロバストなプログラムを、効率の良いC++を使って構成することになります。

 参考のため、各クラスのインスタンスがどのようにメモリ上に配置されるかを図2に示します。

型別のメモリレイアウト 図2 型別のメモリレイアウト



 Symbian OSでは、クラスの作り方のパターンを命名規則(ネーミングコンベンション)で規定しています。ほかの環境では言語でサポートしているGC付きのOOPLとも共通する概念を、Symbian OSでは規約により解決しているわけです。これにより、C++を使いつつ、プログラマーに好き放題想像力を発揮させないセーフな環境が整えられています。

 ただし、これだけでメモリリークのないプログラムを作成できるかというと、そんなことはありません。次回はこれらの規約の上に構築されたSymbian OSの三大特徴の1つ、例外処理にも耐えるメモリ管理フレームワークを解説します。(次回に続く)


前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.