2015-12-14 90 views
1

我在写一个允许建立贝叶斯网络的库。网络的结构被封装并且用户不能访问其字段;但是他们可以获得并设置其中的一些。假设你想为table(基本上是一个双数组)的字段编写访问函数。在以下选项之间,哪个更合适?如何定义一个getter函数

第一选项:

int getTable(Net *net, double *res) 

第二个选项:

double *getTable(Net *net) 

在第一选项中,用户提供一个指针,其中表中的值将被写入阵列。该功能复制res上的表值,使用户无法直接访问内部结构。修改res离开网表不变。当然,提供另一个功能(如getTableSize())可以正确分配res。这似乎是安全的(内部结构保持一致),并且具有如果出现问题就可以返回代码值的优点。缺点是这种方法比下一个方法慢,因为它涉及到一个副本。通常,table的值的数量可能从1到几百不等。

在第二个选项中,函数直接返回指向内部值的指针。在文档中,我将指定用户不能尝试释放指针或修改值。如果执行网络上的其他操作,则释放指针可能会导致分段错误和内存泄漏。修改表格不会导致任何明显的错误,但内部连贯性将被打破,后续计算的结果可能会非常错误,并且很难为用户进行调试。

你更喜欢哪个选项?还有其他的东西需要考虑?还有其他方法可以选择吗?

+3

我会采取前一种方法。这个库的用户可能会有他对动态内存分配的偏好(比如根本不使用它)。 –

+1

IMO两种方法都基于所需的语义有自己的位置。第一种方法由于不暴露内部部件而具有安全的优点,但第二种方法对于容器数据结构的弹出函数 – ForeverStudent

回答

1

个人而言,我会去第一个选项,因为它能够返回错误代码。这也可以解决你的问题,关于用户错误地释放返回的值。将指针传递给堆栈中声明的变量很容易。

请注意,您还可以使事情更清晰,即返回值不能返回一个常量指针这样

const double * getTable(Net *net); 

以这样的方式被修改或释放,与第二个选项,主叫方不能修改这个值,除非他把它转换到一个非const的,但我认为这因为呼叫者会故意打断你的界面,所以会有点过头。对常量性

更多信息,可以发现on wikipedia

+0

关于'const'限定符的好处。出于你提到的原因,我采用了第一种方法。 – nicola

1

我认为一个好习惯是总是要求函数返回的代码可能因某种原因失败。

使用返回码时,错误处理效率更高。

我会选择一个。

另外,我不知道这是否是一个错误或没有,但方案二的回报一个双指针 - 如果这是正确的行为,那么功能一应具备签名:

int getTable(Net *net, double **res) 

此外,作为尤金Sh。在一些评论中提到,有些环境可能甚至不支持malloc(一些嵌入式设备的固件),所以给用户一个选择,以传递一个malloc'd变量还是一个栈分配变量也是一个很好的卖点一。

+0

没有任何错误。 'table'字段只是一个'double'数组。 'res'参数是一个指向数组的指针,它将被填充正确的值。一个典型的用法是'double res [getTableSize(net)]'(或'double * res = malloc(sizeof(double)* getTableSize(net))'),接着是'getTable(net,res)'。 – nicola

1

我有两个点,你要考虑:

  1. 你想要内存释放是在分配在同一个地方。如果你在一个函数中分配内存并返回指针,那么函数的调用者必须知道如何释放它,并且必须记住释放它。保持这种代码将是一场噩梦。

  2. 不成熟的优化是万恶之源。在您确定(即您测量)确切那部分代码导致问题之前,不要优化您的代码。

也就是说,第一个选项是唯一的选择。

+0

同意这两点。要明确,第二种方法_不分配任何内存,因为内存已经存在。它只是返回指向它的指针。提供了一个deleteNet()函数,可以释放与网络相关的所有内存。 – nicola

0

最好的选择是避免无用的分配。 你必须返回适当的信息,例如指针和长度,以及用户的责任,正确使用它。

如果您确实需要阻止用户修改数据,请使用mprotect。