C++と組み込み環境

組み込み環境の開発では、今なおCが主流の開発言語のままです。このブログでは、C++を組み込み環境で使用するためのTips等を集めてみたいと思います。

Latest Entries

例外処理が使えない環境でコンストラクタが失敗したら...

以前、「例外のないC++」ということで、いろいろ考察してみたことがありました。しかし、コンストラクタが失敗したときの解決方法としては、どれもいまいちパッとしません。そこで、改めて、例外処理が使えない環境でコンストラクタが失敗したら、という問題について考えてみることにします。

例外処理が使える環境でも、「例外処理を使いこなせない」、あるいは「例外処理が嫌い」といった事情からか、コンストラクタが失敗した際に、例外を送出する以外の方法を採っているクラスも多く出回っています。それらを見てみると、
  1. オブジェクト内部に失敗した状態を保持しておく。
  2. コンストラクタではほとんど何も行わず、別途初期化用のメンバ関数を用意する。
のどちらかのようです。

このうちの1.は以前考察したときに出した結論ですが、状態確認用のメンバ関数を用意しても、それを呼び出すことを強制することは困難ですし、何か行うたびにその都度内部で確認していたのでは、実装が面倒ですし(当然判定処理の漏れも起こりうる)、パフォーマンスも低下します。

2.は初期化の手順が煩雑になり、C++の思想から外れているように思います。

というわけで、別の方法が必要になりそうです。もし、動的なオブジェクト生成が許されるのであれば、

A* create_A()
{
A* p = new A;
if (p->fail())
return 0;
return p;
}


のような方法もありでしょう。しかし、C++の大きな利点のひとつは、オブジェクトをスタック上に生成できることであり、その利点を失うのはあまりにも代償が大きすぎます。

というわけで、次のような方法はどうでしょうか?

template <class T>
class builder
{
T object_;
public:
T* get()
{
if (object_.fail())
return 0;
return &object_;
}
};

int main()
{
builder<A> b;
if (A* pa = b.get())
{
...
}
}


この方法であれば、getメンバ関数を呼び出さない限り、Aのインスタンスにアクセスできません。また、Aの生成に失敗していれば空ポインタが返ってきますので、誤ってこれを使おうとした場合、比較的早い段階でプログラムがクラッシュします。また、Aのインスタンスはスタック上に生成することができます。

もっと安全性を強化するには、getメンバ関数は生のポインタを返すのではなく、空ポインタに対して->演算子等を使おうとするとassertで落ちるようにしたスマートポインタを使うのもひとつの手です。

template <class T>
class assert_ptr
{
T* ptr_;
public:
explicit assert_ptr(T* ptr) : ptr_(ptr) {}
T* operator->() const
{
assert(ptr_ != 0);
return ptr_;
}
};


難がないわけではありませんが、それなりに効果的な方法ではないかと考えています。

2008-05-05(Mon) | 実装技術 | comment : 0 | Trackback : 0

RAIIイディオム

まともな内容を書くのは約半年ぶりです。ネタはあっても、"大人の事情"というか、安易にブログに書けないことも多くて大変なのですが、何とか頑張ってみたいと思います。長い間更新していないと、過去に何を書いて、何を書いていないのか、さっぱり分からなくなってしまいますが、気にせずに進めることにします。雑誌でも定期的に同じネタを取り上げますので、それと同じようなものですね。

というわけで、今回はRAII(Resource Acquisition Is Initialization)イディオムです。日本語でいえば、「リソースの獲得は初期化」ということになります。そして、「リソースの解放は終期化」ということでもあります。早い話が、コンストラクタでリソースを獲得し、デストラクタで解放するというイディオムです。

RAIIイディオムの代表例はスマートポインタです。コンストラクタでオブジェクトを生成し、デストラクタで解体します。多くのスマートポインタの実装では、コンストラクタの外で new を使ってオブジェクトを生成し、そのポインタを与えるようになっていますが、気持ちとしてはRAIIということです。

他には、排他制御も分かりやすい例でしょう。コンストラクタでロックをかけ、デストラクタでロックを解除します。途中でエラーが発生して、いきなりリターンしても、例外が送出されても、有効範囲から抜ける際に確実にロックが解除できます。

RAIIイディオムでは、オブジェクトが生成されてから解体されるまでの間、リソースを保持していることが保証されます。ということは、コンストラクタに失敗してリソースが獲得できなかった場合には、例外を送出して、強制的に有効範囲の外に飛び出すようにしなければなりません。

あるいは、生成したオブジェクトへのポインタを返す関数を用意して、リソースの獲得に成功したかどうかを最初に判定する必要があるでしょう。とりあえずオブジェクトを生成して、その後で通常のメンバ関数を呼び出してリソースの獲得を行うのは、もはやRAIIイディオムとはいえません。

実際には例外が使えない状況も多いので、失敗する可能性がある場合にRAIIイディオムを使うのは難しいこともあるでしょう。そこで次回は、例外が使えない環境で、コンストラクタからの例外送出に変わる方法を取り上げてみたいと思います。最近思いついた方法なので、いろいろ穴があると思います。気付いた方は突っ込んでみてください。

2008-04-09(Wed) | 実装技術 | comment : 0 | Trackback : 0

保守投稿

長い間更新が滞っていると、FC2ブログではスポンサー広告が表示されてしまい、タイトルバーの内容も「::スポンサー広告」となってしまうようです。検索エンジンでも「::スポンサー広告」と表示されてしまうため、何かとご不便をおかけする結果になってしまいました。

というわけで、ネタはなくても、ときどき保守投稿を行うことにします。内容は皆無ですが、上記のような事情ですのでご理解ください。できれば、新ネタを書けるように努力しますので、気長にお付き合いください。

2008-03-24(Mon) | 未分類 | comment : 0 | Trackback : 0

データメンバを公開するのも、時には方便

純粋な構造体を除き、データメンバは常に非公開にするのは、クラス設計のイロハのようなものです。しかし、時には禁忌を犯してみるのもよいのかもしれません。それは次のような理由からです。

データメンバを非公開にしている以上、オブジェクトの初期化は必ずコンストラクタによらなければなりません。しかし、コンストラクタを用いて動的に初期化する場合、そのオブジェクトを ROM に配置することは不可能になります。

オブジェクトの宣言時に const 修飾子を付けて静的記憶域期間を持たせる場合、おそらくはそれが ROM に配置されることを期待してのことでしょう。だとすると、動的な初期化しかできないのは都合が悪いことになります。

ところで、C++ の次期標準規格に導入される予定の std::tr1::array クラステンプレートは、データメンバが公開されています。ですから、

std::tr1::array const a = { 1, 2, 3 };

のように初期化子を与えて、静的に初期化することが可能です。このクラステンプレートは struct を使って定義されますが、構造体と呼ぶには、コンテナの要件を満たすメンバ関数が一通り用意されており、やや無理があります。

データメンバが公開されていないクラスには class を、データメンバを公開しているクラスには struct を用いるなどして、一見してそのクラスの持つ性質が分かるような工夫をするのもよいかと思います。

2007-09-11(Tue) | 実装技術 | comment : 6 | Trackback : 0

本ブログの記事をまとめ始めています。

長い間放置状態で申し訳ありません。今後もこのブログは継続するつもりではいるのですが、過去の記事を http://www.kijineko.co.jp/tech/cppemb にまとめ始めました。記事を書いてからある程度の期間が経過していることもあり、そのときは気づいていなかったことなども、同時に盛り込んでいけたらと考えています。

現時点で掲載している3ページに限っても、それなりに加筆・修正を行っています。今後あちらのサイトでは、あまり重要でない記事は思い切って削除するか、別のところに改めてまとめることにして、より洗練された構成にしていければと考えています。一方、このブログでは、思いつくままいろいろなことを書いていきたいと思います。

2007-06-19(Tue) |  | comment : 0 | Trackback : 0

Page Top▲

Navigation

インフォメーション


人気blogランキングへ
ブログランキングranQ

プロフィール

Author:高木信尚
ホームページ
ブログ

カレンダー
04 | 2008/05 | 06
- - - - 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
最近のコメント
最近のトラックバック
月別アーカイブ
カテゴリー
リンク
このブログをリンクに追加する
ブロとも申請フォーム

この人とブロともになる