私はCライブラリに取り組んでおり、その一部はいくつかの数学タイプを扱い、それらを操作しています。各タイプには、動的に割り当ておよび解放するファクトリコンストラクタ/デストラクタ関数があります。例えば:
/* Example type, but illustrates situation very well. */
typdef struct {
float x;
float y;
float z;
} Vector3D;
/* Constructor */
Vector* Vector3D_new(float x, float y, float z) {
Vector3D* vector = (Vector3D*) malloc(sizeof(Vector3D));
/* Initialization code here...*/
return vector;
}
/* Destructor */
void Vector3D_destroy(Vector3D* vector) {
free(vector);
}
素晴らしくシンプルで、ユーザーの適切な初期化の負荷を軽減します。
ここでの私の主な関心事は、これらの型を操作する関数の処理方法(具体的には結果値を返す方法)です。ほとんどすべての二項演算は同じ型の新しいインスタンスになるため、これをどのように与えるかを検討する必要があります。ユーザーに戻ります。値で返すこともできますが、より高速で、construct / destructorメソッドと互換性があり、ユーザーにそれほど負担をかけないため、ポインターを渡すことをお勧めします。
現在、関数に結果を動的に割り当てて、それへのポインターを返すことで実装しています。
/* Perform an operation, and dynamically return resultant vector */
Vector3D* addVectors(Vector3D* a, Vector3D* b) {
Vector3D* c = Vector3D_new(
a->x + b->x,
a->y + b->y,
a->z + b->z);
return c;
}
値をユーザーに直接返すことにより、次のようにチェーン化できる(たとえば、パラメーターとして別の関数に直接渡される)ことができるという利点があります。
/* Given three Vector3D*s : a, b, & c */
float dot = dotProduct(crossProduct(a, addVectors(b, c));
しかし、現在の方法を考えると、結果がにaddVectors()
直接渡されcrossProduct()
、ユーザーがそれに渡される機会がないため、これによりメモリリークが発生します(そして、に渡される結果free()
と同じことが起こります)。これを機能させるには、値を保持するためのポインターを作成し、それを使用してから、そのポインターを介してそれを使用する必要があります。crossProduct()
dotProduct()
free()
Vector3D* d = addVectors(b, c);
Vector3D* e = crossProduct(a, d);
float dot = dotProduct(e);
Vector3D_destroy(d);
Vector3d_destroy(e);
これは機能しますが、直感的ではなく、私が望む連鎖効果を失います。
もう1つの可能性は、操作関数に3つの引数を取るようにすることです。2つはオペランド用で、もう1つは結果を格納するためのものですが、やはりあまり直感的ではありません。
私の質問は次のとおりです 。二項演算で動的メモリを操作するためのエレガントで生産的な方法は何ですか?ボーナスとして、実際のライブラリで使用されているソリューションはかなりクールです。何か案は?:)