我正在编写一个允许构建贝叶斯网络的库。网络的结构被封装,用户无法访问其字段;但他们可以得到并设置其中一些。假设你想为字段table
(基本上是一个双数组)编写访问器函数。在以下选项之间,哪个更合适?
第一个选项:
int getTable(Net *net, double *res)
第二个选项:
double *getTable(Net *net)
在第一个选项中,用户提供指向将写入表值的数组的指针。该函数在res
上复制表值,使用户无法直接访问内部结构。修改res
会使网络表保持不变。当然,提供了另一个函数(比如getTableSize()
)来正确分配res
。这似乎是安全的(内部结构保持连贯)并且具有以下优点:如果出现问题,您可以返回代码值。缺点是这种方法可能比下一种方法慢,因为它涉及一个副本。通常,table
的值的数量可能从1到几百不等。
在第二个选项中,函数直接返回指向内部值的指针。在doc中,我将指定用户不能尝试释放指针或修改值。如果执行网络上的其他操作,释放指针可能会导致分段错误和内存泄漏。修改表不会导致任何明显的错误,但内部一致性将被破坏,后续计算的结果可能非常错误,并且很难为用户调试。
您更喜欢哪个选项?还有其他要考虑的事情吗?还有其他方法可供选择吗?
答案 0 :(得分:1)
我认为一个好习惯是总是要求函数返回代码,因为某些原因可能会失败。
使用返回代码时,错误处理效率更高。
我选择第一选。
另外,我不知道这是不是错误,但是选项2返回一个双指针 - 如果这是正确的行为,那么函数1应该有签名:
int getTable(Net *net, double **res)
此外,正如Eugene Sh。在评论中提到,某些环境可能甚至不支持malloc(一些嵌入式设备固件会浮现在脑海中),因此让用户选择是否传入malloc'd变量或堆栈分配变量也是一个很好的选择卖点。之一。
答案 1 :(得分:1)
就个人而言,我会选择第一个选项,因为它能够返回错误代码。这也可以解决您的用户错误地释放返回值的问题。并且在栈上声明的变量上传递指针很容易。
请注意,您也可以使事情更清晰,即无法修改或释放返回的值,使用第二个选项返回一个这样的const指针
const double * getTable(Net *net);
通过这种方式,调用者无法修改该值,除非他将其转换为非const,但我认为这会因为调用者故意破坏你的界面而有点过分。
有关constness的更多信息,请on wikipedia
答案 2 :(得分:1)
我有两点要考虑:
您希望内存释放与分配所在的位置相同。如果在函数中分配内存并返回指向它的指针,那么函数的调用者必须知道如何释放它,必须记住释放它。保持这种代码将是一场噩梦。
过早优化是所有邪恶的根源。在您确定(即您已经测量)确切的代码部分导致问题之前,不要优化您的代码。
那就是说,第一种选择是唯一的选择。
答案 3 :(得分:0)
最好的选择是避免无用分配。 您必须返回相应的信息,例如指针和长度,以及用户有责任正确使用它。
如果您确实需要阻止用户修改数据,请使用mprotect。