Cで「デストラクタ」を省略すると、YAGNIが過度に影響を受けますか?


9

私はOOのようなテクニックを使用して、Cで中程度の組み込みアプリケーションに取り組んでいます。私の「クラス」は.h / .cモジュールであり、データ構造体と関数ポインタ構造体を使用して、カプセル化、ポリモーフィズム、および依存性注入をエミュレートします。

これで、myModule_create(void)関数にmyModule_destroy(pointer)対応する関数が付属することが期待されます。しかし、プロジェクトが埋め込まれている場合、現実的にインスタンス化されたリソースは決して解放されるべきではありません。

つまり、4つのUARTシリアルポートがあり、必要なピンと設定を使用して4つのUARTインスタンスを作成する場合、ランタイム中のある時点でUART#2を破棄する必要はまったくありません。

YAGNI(あなたはそれを必要としないでしょう)の原則に従って、私はデストラクタを省略すべきですか?これは私には非常に奇妙に思えますが、それらの使用法を考えることはできません。デバイスの電源がオフになると、リソースは解放されます。


4
オブジェクトを破棄する方法を提供しない場合、作成されたオブジェクトには「無限」の存続期間があることを示す明確なメッセージが渡されます。これがあなたのアプリケーションにとって理にかなっているなら、私は言う:それをしてください。
2014

4
型を特定のユースケースに結び付けるのにこれほど遠くまで行くつもりなら、なぜmyModule_create(void)関数があるのか 使用する予定の特定のインスタンスを、公開するインターフェースにハードコードするだけで済みます。
ドヴァル2014

@ドヴァル私はそれについて考えました。私は上司からのコードの一部とビットを使用するインターンなので、「正しく実行する」、CでOOスタイルを実験的に経験し、会社の標準との整合性を保つために取り組んでいます。
アシックス2014

2
@glampertはそれを釘付けします。create関数のドキュメントで、予想される無限のライフタイムをクリーンにする必要があることを付け加えます。
Blrfl 2014

回答:


11

オブジェクトを破棄する方法を提供しない場合、作成されたオブジェクトには「無限」の存続期間があることを示す明確なメッセージが渡されます。これがあなたのアプリケーションにとって理にかなっているなら、私は言う:それをしてください。

グランパートは正しい。ここではデストラクタは必要ありません。彼らは、ユーザーに対してコードの膨張と落とし穴を作成するだけです(デストラクタが呼び出された後にオブジェクトを使用することは、未定義の動作です)。

ただし、オブジェクトを破棄する必要がないことを確認する必要があります。たとえば、現在使用されていないUARTのオブジェクトが必要ですか?


3

メモリリークを検出するために私が見つけた最も簡単な方法は、アプリケーションをきれいに終了できるようにすることです。多くのコンパイラ/環境は、アプリケーションの終了時にまだ割り当てられているメモリをチェックする方法を提供します。コードが提供されない場合、終了する直前にコードを追加する方法があり、それを理解することができます。

したがって、組み込みシステムでも、メモリリークの検出を容易にするために「理論的に」決して終了してはならないコンストラクタ、デストラクタ、およびシャットダウンロジックを確実に提供します。実際には、アプリケーションコードが終了してはならない場合、メモリリークの検出はさらに重要です。


これは、割り当てを行うのが起動時のみである場合には当てはまりません。これは、メモリ制約デバイスで私が真剣に検討するパターンです。
CodesInChaos 2014

@コード:自分を制限する理由はありません。起動時にメモリを事前に割り当てる優れたデザインを思い付くかもしれませんが、この壮大な計画に精通していないか、その重要性を理解していない人が来たとき、彼らはメモリを割り当てます飛んで、あなたのデザインがあります。それを正しく行い、割り当て/割り当て解除して、実装したものが実際に機能することを確認してください。本当にメモリに制約のあるデバイスがある場合、通常行われるのは、新しいoperator / mallocをオーバーライドして、割り当てブロックを事前予約することです。
2014

3

OOのようなアプローチを促進するために不透明なデータ型を広範囲に使用する私の開発では、私もこの質問に取り組みました。当初、私は明らかにYAGNIの観点から、およびMISRAの「デッドコード」の観点から、デストラクタを排除する陣営にいた。(私には十分なリソースの余地があり、それは考慮事項ではありませんでした。)

ただし、デストラクタがないため、自動化されたユニット/統合テストのように、テストがさらに困難になる可能性があります。従来は、各テストはセットアップ/ティアダウンをサポートしているため、オブジェクトを作成、操作、破棄できます。それらは、次のテストのためのクリーンで汚染されていない開始点を保証するために破壊されます。これを行うには、クラスにデストラクタが必要です。

したがって、私の経験では、YAGNIの「aint't」は「are」であることが判明し、必要かどうかにかかわらず、すべてのクラスにデストラクタを作成することになりました。テストをスキップしたとしても、少なくとも正しく設計されたデストラクタが存在し、それに続く貧弱なslobが存在します。(そして、はるかに小さい値にすると、破壊される環境で使用できるため、コードの再利用性が高まります。)

これはYAGNIに対処しますが、デッドコードには対処しません。そのため、#define BUILD_FOR_TESTINGのような条件付きコンパイルマクロを使用すると、デストラクタを最終的な製品ビルドから削除できることがわかります。

このように行うと、テスト/将来の再利用のためのデストラクタがあり、YAGNIの設計目標と「デッドコードなし」のルールを満たします。


テスト/製品コードを#ifdefすることに注意してください。あなたが説明したように、関数全体に適用した場合、それは合理的に安全です。なぜなら、関数が実際に必要な場合、コンパイルは失敗するからです。ただし、関数内で#ifdefをインラインで使用すると、prodで実行されているコードパスとは異なるコードパスをテストしているので、はるかに危険です。
ケビン

0

あなたは次のような何もしないデストラクタを持つことができます

  void noop_destructor(void*) {};

次に、Uartおそらく使用するデストラクタを設定します

  #define Uart_destructor noop_destructor

(必要に応じて適切なキャストを追加してください)

文書化することを忘れないでください。多分あなたも欲しい

 #define Uart_destructor abort

または、デストラクタポインタ関数がデストラクタNULLを呼び出さないようにする場合の、デストラクタを呼び出す一般的なコードの特殊なケース。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.