[英]How should I return the result of a binary-operation function in a C library?
我正在研究一個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);
}
簡單,簡單,也減輕了用戶正確初始化的負擔。
現在我主要關注的是如何處理對這些類型進行操作的函數(特別是如何返回結果值。)幾乎每個二進制操作都會產生一個相同類型的新實例,因此,我需要考慮如何給出這個回到用戶。 我可以按值返回事物,但是傳遞指針會更受歡迎,因為它更快,與構造/析構函數方法兼容,並且不會給用戶帶來太多負擔。
目前我通過讓函數動態分配結果,然后返回指向它的指針來實現它:
/* 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);
這樣可行,但不那么直觀,並且失去了我所希望的鏈接效果。
另一種可能性是使操作函數有3個參數; 兩個用於操作數,一個用於存儲結果,但同樣不是很直觀。
我的問題是:在二進制操作中使用動態內存有哪些優雅和富有成效的方法? 作為獎勵,已經在現實世界圖書館中使用的解決方案將非常酷。 有任何想法嗎? :)
除了您提到的內存泄漏之外,您當前的系統還存在一些其他問題:
- 分配給堆的速度明顯慢於普通堆棧操作。
- 每個分配也需要是
free()
d,這意味着每個實例都需要至少2個函數調用,其中只使用基於堆棧的設計將不需要。- 由於內存必須手動管理,因此會留下更多的內存泄漏空間。
- 內存分配可能會失敗! 基於堆棧的系統可以緩解這種情況。
- 使用指針需要解除引用。 這比直接訪問慢,並且需要更多(也許是草率)sytax。
除此之外,許多編譯器緩存用於程序堆棧的內存,並且可以在堆上提供顯着的改進(幾乎從不緩存(如果可能!))
簡而言之,只需依靠堆棧就可以獲得最佳性能,不僅僅是性能,還有維護和清潔代碼。 唯一要記住的是堆棧是有限的,它也可能很容易變得瘋狂。 將堆棧用於短期數據(在這種情況下為二進制運算結果),堆用於較長的長期數據。
我希望這有幫助! :)
注意:這個答案的大部分內容都歸功於@Justin 。
在操作員內部分配並不像看起來那么方便。
這主要是因為您沒有垃圾收集,也因為您不得不擔心分配失敗。
考慮以下代碼:
Vector3D *v1,*v2,*v3;
Vector3d v4 = addVectors(v1,multiplyVectors(v2,v3));
看起來很好。
但是從multiplyVectors
返回的向量會發生什么? 內存泄漏。
如果分配失敗會發生什么? 一些其他功能崩潰。
我會在原地添加:
void addVectors(Vector3D *target, const Vector3D *src);
這相當於target += src;
。
我會這么簡單
Vector3D addVectors(Vector3D a, Vector3D b) {
Vector3D c;
c.x = a.x + b.x;
c.y = a.y + b.y;
c.z = a.z + b.z;
return c;
}
如果調用者真的需要它在堆上,他可以自己復制它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.