我对如何在C中正确实现对象有疑问。
事实是我从更容易发生内存泄漏的方法返回对象,例如,永远不会返回一个对象并在参数列表中通过引用这样做吗?
extern void quaternion_get_product(Quaternion * this, Quaternion * q, Quaternion * result);
这样malloc()
调用只在构造函数中完成,因此更容易控制。
我是C中这种封装的新手,所以我不确定这是否是解决我问题的方法。我只是希望我的代码可以扩展,而且我看到如果我继续这样做,内存泄漏将会出现,而且调试真的很难。通常如何接近?我的代码是否在正确的轨道上?
我的问题是,如果我有这个:
Quaternion p = *quaternion_create(1, 0, 0, 0);
Quaternion q = *quaternion_create(1, 0, 1, 0);
Quaternion r = *quaternion_create(1, 1, 1, 0);
Quaternion s = *quaternion_create(1, 1, 1, 1);
p = *quaterion_get_product(&p, &q); // Memory leak, old p memory block is not being pointed by anyone
Quaternion t = *quaternion_get_product(&q, quaternion_get_product(&s, &r));
嵌套函数调用时存在内存泄漏,中间内存块未被任何现有指针指向,无法调用quaternion_destroy
标题文件:
#ifndef __QUATERNIONS_H_
#define __QUATERNIONS_H_
#include <stdlib.h>
typedef struct Quaternion Quaternion;
struct Quaternion {
float w;
float x;
float y;
float z;
};
extern Quaternion *quaternion_create(float nw, float nx, float ny, float nz);
extern void quaternion_destroy(Quaternion *q);
extern Quaternion *quaternion_get_product(Quaternion *this, Quaternion *q);
extern Quaternion *quaternion_get_conjugate(Quaternion *this);
extern float quaternion_get_magnitude(Quaternion *this);
extern void quaternion_normalize(Quaternion *this);
extern Quaternion *quaternion_get_normalized(Quaternion *this);
#endif
实施文件:
#include "quaternion.h"
#include <math.h>
Quaternion *quaternion_create(float nw, float nx, float ny, float nz) {
Quaternion *q = malloc(sizeof(Quaternion));
q->w = nw;
q->x = nx;
q->y = ny;
q->z = nz;
return q;
}
void quaternion_destroy(Quaternion *q) {
free(q);
}
Quaternion *quaternion_get_product(Quaternion *this, Quaternion *p) {
Quaternion *return_q = quaternion_create(
this->w * p->w - this->x * p->x - this->y * p->y - this->z * p->z, // new w
this->w * p->x + this->x * p->w + this->y * p->z - this->z * p->y, // new x
this->w * p->y - this->x * p->z + this->y * p->w + this->z * p->x, // new y
this->w * p->z + this->x * p->y - this->y * p->x + this->z * p->w
);
return return_q;
}
Quaternion *quaternion_get_conjugate(Quaternion *this)
{
return quaternion_create(this->w, -this->x, -this->y, -this->z);
}
float quaternion_get_magnitude(Quaternion *this) {
return sqrt(this->w * this->w + this->x * this->x + this->y * this->y + this->z * this->z);
}
void quaternion_normalize(Quaternion *this) {
float m = quaternion_get_magnitude(this);
this->w /= m;
this->x /= m;
this->y /= m;
this->z /= m;
}
Quaternion *quaternion_get_normalized(Quaternion *this) {
Quaternion *r = quaternion_create(this->w, this->x, this->y, this->z);
quaternion_normalize(r);
return r;
}
答案 0 :(得分:3)
实际上,如果某个函数更新某些东西的两个副作用并返回一个新构造的值,它会变得更糟。比如,谁记得scanf
返回一个值?
关注GNU Multi Precision Arithmetic Library我建议以下是一个合理的解决方案(实际上,它们会让内存分配变得更加令人头痛,而不是图书馆):< / p>
+
的两边)和输出参数(放置结果的位置,覆盖之前对象中的所有内容),如下所示: mpz_add (a, a, b); /* a=a+b */
通过这种方式,您将始终清楚地看到何时创建/销毁对象,并确保没有泄漏或双重释放。当然,这会阻止你进行链接#34;多个操作一起使您可以手动管理临时变量以获得中间结果。但是,我相信您仍然必须在C中手动执行此操作,因为即使编译器也不太了解动态分配的变量的生命周期。
实际上,如果我们不离开。 3并添加&#34;库不管理内存&#34;条款,我们将得到更容易出错的解决方案(从库的角度来看),这将要求库的用户管理他们想要的内存。这样你也不会使用malloc
/ free
内存分配来锁定用户,这是一件好事。
答案 1 :(得分:1)
无需动态分配您的季度。四元数具有固定的大小,因此您只能使用普通的四元数。如果进行整数计算,则只使用int
s而不为每个int
动态分配空间。
不使用malloc/free
(未经测试的代码)的想法
Quaternion quaternion_create(float nw, float nx, float ny, float nz) {
Quaternion q;
q.w = nw;
q.x = nx;
q.y = ny;
q.z = nz;
return q;
}
Quaternion quaternion_get_product(Quaternion *this, Quaternion *p) {
Quaternion return_q = quaternion_create(
this->w * p->w - this->x * p->x - this->y * p->y - this->z * p->z, // new w
this->w * p->x + this->x * p->w + this->y * p->z - this->z * p->y, // new x
this->w * p->y - this->x * p->z + this->y * p->w + this->z * p->x, // new y
this->w * p->z + this->x * p->y - this->y * p->x + this->z * p->w
);
return return_q;
}
用法
Quaternion p = quaternion_create(1, 0, 0, 0);
Quaternion q = quaternion_create(1, 0, 1, 0);
Quaternion r = quaternion_create(1, 1, 1, 0);
Quaternion s = quaternion_create(1, 1, 1, 1);
p = quaterion_get_product(&p, &q);
Quaternion t = quaternion_get_product(&q, quaternion_get_product(&s, &r));
没有malloc
和free
,因此没有可能的内存泄漏,性能会更好。
答案 2 :(得分:1)
在我看来你说错了。
您还需要检查malloc()是否返回NULL并处理该失败(例如通过显示内存不足错误消息并退出,如果失败,因为这通常是不可恢复的)。
<强>更新强>
由于您需要释放中间结果,因此您必须采取更多操作来保留指针。
更新2
@MichaelWalz方法很棒。如果你不需要,为什么要处理所有的分配和指针管理?但是,如果你做使用指针并分配内存,你必须保留指针,并确保你释放东西并传递它们/仔细重用它们。我已经更新了我的例子来处理嵌套调用。更新3
我不得不从函数调用参数中删除&amp; s,因为你传入了指针,这些指针已经是你想要指向的地址了。您没有正确分配函数的输出。请注意固定示例中指针分配的不同之处。
Quaternion p = *quaternion_create(1, 0, 0, 0);
Quaternion q = *quaternion_create(1, 0, 1, 0);
Quaternion r = *quaternion_create(1, 1, 1, 0);
Quaternion s = *quaternion_create(1, 1, 1, 1);
p = *quaterion_get_product(&p, &q); // Memory leak, old p memory block is not being pointed by anyone
Quaternion t = *quaternion_get_product(&q, quaternion_get_product(&s, &r));
Quaternion *p = quaternion_create(1, 0, 0, 0);
Quaternion *q = quaternion_create(1, 0, 1, 0);
Quaternion *r = quaternion_create(1, 1, 1, 0);
Quaternion *s = quaternion_create(1, 1, 1, 1);
Quaternian *tmp = quaterion_get_product(p, q);
quaternian_destroy(p);
p = tmp;
tmp = quaternion_get_product(s, r)
Quaternion *t = quaternion_get_product(q, tmp);
quaternian_destroy(tmp);