newを使用せずにC ++でFactory Methodパターンを実装できますか?
-
06-07-2019 - |
質問
組み込み環境(Arduino / AVR ATMega328)で作業しており、C ++でFactory Methodパターンを実装したい。ただし、私が使用しているコンパイラ(avr-gcc)は、 new
キーワードをサポートしていません。 new
を使用せずにこのパターンを実装する方法はありますか?
解決
AVRコンパイラはgccコンパイラに基づいているため、新しいキーワードをサポートする可能性が非常に高くなります。正確なエラーは何ですか。未定義の関数、つまり演算子newの行に沿ったリンク/コンパイラエラーだと思います。 new演算子とoperator newには違いがあります。最初の演算子はオブジェクトの作成に使用され、後者はオブジェクトのメモリの割り当てに使用されます。 new演算子は、作成されるオブジェクトのタイプに対してoperator newを呼び出し、オブジェクトのvテーブルを初期化し、オブジェクトのコンストラクターを呼び出します。 このFAQを読む演算子newは標準ライブラリ。これは簡単に修正できます。定義するだけです:
void *operator new (size_t size)
{
return some allocated memory big enough to hold size bytes
}
そして削除も定義する必要があります:
void operator delete (void *memory)
{
free the memory
}
追加する唯一のものは、メモリ管理、メモリブロックの割り当てと解放です。これは、割り当てられた既存のメモリ(コード、静的/グローバルデータ、スタック)を上書きしないように注意して、簡単に実行できます。 2つのシンボルを定義する必要があります。1つは空きメモリの開始用、もう1つは空きメモリの終了用です。この領域でメモリのチャンクを動的に割り当てたり、解放したりできます。このメモリを自分で管理する必要があります。
他のヒント
実行時にクラスをインスタンス化する方法がない場合、これは不可能だと思います。できることは、コンパイル時にいくつかのオブジェクトを事前に割り当て、それらへの参照を作成し、必要なときにそれらを返すことだけです。
Factory Methodの全体像はオブジェクト作成であり、これはヒープメモリの消費を意味します。組み込みシステムでは、RAMに制約されており、メモリの制限を考慮して設計上のすべての決定を行う必要があります。 ATmega328には2 KBのRAMしかありません。このような狭いスペースで動的に割り当てられたメモリを使用しないことをお勧めします。
あなたの問題をより詳細に知ることなく、クラスのいくつかのインスタンスを静的に宣言し、それらのインスタンスを何らかの方法で再利用することをお勧めします。これは、オブジェクトがいつ、なぜ作成されるか、そして(重要なだけとして)いつ、なぜ終了するかを知る必要があることを意味します。一度にアクティブにする必要がある数と、一度にアクティブにすることができる数を把握する必要があります。
!!ディーン
このようなものはどうですか?
MyClass *objp = (MyClass*)malloc(sizeof(MyClass));
*objp = MyClass(); // or any other c'tor
編集:言及し忘れましたが、MyClassには代入演算子があると仮定しています。
EDIT2:私が忘れていたもう1つのこと-はい、落とし穴があります(C ++で、常に落とし穴があります)。無料では使用できないため、オブジェクトのd'torを手動で呼び出す必要があります。
ファクトリを使用している場合、いくつかの仮想関数があることを示す動的バインディング動作が必要であることを意味します。 malloc()を使用してオブジェクトにメモリを割り当てることは可能かもしれませんが、クラスのvtableは適切にセットアップされないため、仮想関数の呼び出しはクラッシュします。動的バインディングが必要な場合、これを行う方法はありません。
mallocを実行できますか?その場合は、その方法でオブジェクトをmallocできます。
また、ファクトリから作成するオブジェクトの性質は何ですか?
- それらはimutableですか?
- ファクトリは、コンパイル時に認識できる限定されたオブジェクトのセットのみを生成することを目的としていますか?
両方の質問に対する答えが「はい」の場合、不変オブジェクトのセットにメモリを静的に割り当て、ファクトリメソッドが適切なオブジェクトへのポインタを返すようにすることができます。
どちらの質問にも答えがノーの場合、これは機能しません。また、このアプローチでは、常にそのメモリが割り当てられるという問題があります。
厳格なコーディング標準(「新規」または「削除」の使用が許可されていない)を備えた組み込みシステムでこの問題を解決した方法は、目的のオブジェクトの静的配列を作成することでした。そして、すでに割り当てられているオブジェクトへの静的ポインターを使用して、これらの戻り値を(静的変数やメンバー変数を使用して)保存し、後でさまざまなオブジェクトを実行します。
// Class File ---------------------------------------------------
class MyObject {
public:
MyObject* getObject();
private:
const int MAX_POSSIBLE_COUNT_OF_OBJECTS = 10;
static MyObject allocatedObjects[MAX_POSSIBLE_COUNT_OF_OBJECTS];
static allocatedObjectIndex = 0;
};
// Implementation File ------------------------------------------
// Instantiate a static array of your objects.
static MyObject::allocatedObject[MAX_POSSIBLE_COUNT_OF_OBJECTS];
// Your method to return already created objects.
MyObject* MyObject::getObject() {
if (allocatedObjectIndex < (MAX_POSSIBLE_COUNT_OF_OBJECTS - 1)) {
return allocatedObjects[allocatedObjectIndex++];
} else {
// Log error if possible
return NULL;
}
}
あらかじめご了承ください。 8か月以上C ++を書いていないので、これはすべてメモリからです。
注:これには、コンパイル時に大量のRAMを割り当てるという重大な欠点があります。