我该如何在C库中返回二元运算函数的结果?

我正在研究一个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返回的向量会发生什么? 内存泄漏。
如果分配失败会发生什么? 一些其他function崩溃。

我会在原地加入:
void addVectors(Vector3D *target, const Vector3D *src);
这相当于target += src;

我会这么简单

 Vector3D addVectors(Vector3D a, Vector3D b) { Vector3D c; cx = ax + bx; cy = ay + by; cz = az + bz; return c; } 

如果调用者确实需要它,他可以自己复制它。