(8)文字列の扱い(コンテナによるオブジェクトの受け渡し)
AVR の C++ には STL が無いので、std::string を使う事はできませんが、文字列を確保する簡単なコンテナを実装して、それを使う事は出来ると思います、またネットを探せば、std::string に似せた実装のいくつかを見つけられると思います。
※動的に確保が必要な文字列が必要無いのであれば、以下の項目はスルーして下さい、しかしながら、常に固定化された文字列だけ扱えば良い場合と言うのも稀と思います。
※std::string が使える環境で、あえて、同じような文字列のコンテナを使う意味は全くありません(ゲームの開発者などに多いようですが、std::string より優秀なクラスを設計して実装し、動作確認をするには、極めて莫大な時間と労力を消費すると思います)、std::string は極めて正しく実装されており、std::string より優れた実装を行う事は殆ど不可能に近いと思います、これは、STL を理解していない「一知半解」と言うべき愚かな行為です。
※メモリーの断片化を避けて、独自の記憶割り当てを行いたい為に、独自の string クラスを作る人がいますが、そんな事をしなくても、アロケーターを実装して、それを渡せば良いのです、std::string が仕様的に不適格で、別の実装を考えなければならない場合は通常殆どありません。
C 言語から C++ を始めて間もない頃は、文字列をやりとりする場合などに、std::string と char* をチャンポンで使った実装をする事が多いと思います、ですがー、コンテナを使った方法論に移行すべきタイミングです。
コンテナを使って返す事で、余分にコピーが発生するので、速度が落ちると考えるかもしれませんが、最適化以前に、より良い設計を心がけるべきで、最適化はその後です。
※通常、コンテナの受け渡しは参照によって行われるので、コピーが発生するのは、最小限となります。
※ AVR の gcc では std::string が使えないので、勉強と、STL 理解の目的で、string クラスを実装してみるのは有益だと思います、仕様は、std::string を元にすれば良いし、テンプレートの作り方などを習得できます、同じ物を作るのはハードルが高いので、自分に必要な機能だけ実装それば良いと思います。
実際には、AVR では、メモリー領域が物理的に分かれている為、ROM 上(コード領域)の場合と、RAM 上の場合で、別々の処理を行う必要があるので、簡単では無いのですが・・
class aaa { // 内部で扱うコンテナや変数は「private」にし、外部に公開する場合は、必ずアクセサーを使ってアクセスするように設計します。 std::string text_; public: // const 参照で受けて・・ void put(const std::string& text) { text_ = text; } // const 参照を返す・・ const std::string& get() const { return text_; } // ポインターを返す仕様なら、条件が「偽」なら、0(NULL ポインター)を返せば、シンプルと思うかもしれませんが、ソースがコンテナであるのに、そのポインターを返すのでは二度手間になる場合があります、やはり、統一的にコンテナとして扱えた方が利便性が高いので、「偽」の場合に、空のコンテナを返すようにすれば、コンテナとして統一的に扱えます。 const std::string& test(char ch) const { if(!text_.empty() && text_[0] == ch) { return text_; } else { static std::string empty; return empty; } } // 固定の文字列を返すのなら「const char*」で返すのは問題無いでしょう。 const char* name() const { return "aaa"; } }; int main() { aaa a; a.put("abcdefg"); ///< std::string は、「=」オペレーターで「char*」型も受け取れるように実装されている。 std::string b("qwert"); a.put(b); ///< もちろん、std::string を受け取る事も出来る。 { const std::string& t = a.get(); if(!t.empty()) { } } { const std::string& t = a.test('a'); if(t.empty()) { } else { } } }
(9)avr-g++ の制限と回避
avr-g++ は、stdc++ ライブラリーが無い為、通常標準で備わっている事が出来ませんので、それら使う場合は個別に実装する必要があるようです。
・new、delete
void * operator new(size_t size) { return malloc(size); } void operator delete(void * ptr) { free(ptr); }
・また場合によっては、スレッドセーフの機構を呼び出すコードが追加されますので、以下のコードも追加します。
__extension__ typedef int __guard __attribute__((mode (__DI__))); extern "C" int __cxa_guard_acquire(__guard *); extern "C" void __cxa_guard_release (__guard *); extern "C" void __cxa_guard_abort (__guard *); int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);}; void __cxa_guard_release (__guard *g) {*(char *)g = 1;}; void __cxa_guard_abort (__guard *) {};
・最後に、仮想関数用のコードを追加します。
extern "C" void __cxa_pure_virtual(void); void __cxa_pure_virtual(void) {};
これで、ほぼ遜色無く、C++ のコードをコンパイル出来るハズです。