簡體   English   中英

我該如何在C庫中返回二元運算函數的結果?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM