bool is_something_ok(int param,SomeStruct* p)
{
bool is_ok = false;
// check if is_ok
if(is_ok)
// set p to some valid value
else
// set p to NULL
return is_ok;
}
如果“确实没事”,此函数返回true并将p设置为有效值 否则返回false并将p设置为NULL
这是一个好的或坏的设计?个人,我使用它时感到不舒服。 如果没有文件和评论,我真的不知道如何使用它。
BTW:是否有一些关于API设计的权威书籍/文章?答案 0 :(得分:13)
由于您已将问题标记为C ++而不是C,我建议您:
但这只是一些一般提示。最好的方法取决于具体的问题......
答案 1 :(得分:3)
取决于您希望如何处理'错误'。
例如,采用标准函数atoi。它将字符串转换为整数,但如果字符串不包含数字,它应该返回什么?在这种情况下,C / C ++运行时将设置errno全局变量。另一种方法是抛出异常。
就个人而言,我并不喜欢这两种选择。 因此,如果我通常使用以下规则:
答案 2 :(得分:2)
我倾向于这样做。 您的示例中的替代方法是将两个事物编码为一个返回值(例如,使用NULL作为特殊值)或返回结构。
编码两件事有时是不可能的,而且容易出错。返回结构是一项额外的工作和混乱。所以我倾向于做你做过的事。我倾向于假设参数列表中的“原始”指针和引用用于返回值,如果它们仅用于传入数据,它们将是“const”。
但说实话,我经常忘记这条规则,所以也许这不是一个很好的规则。
升级库中有一个类“可选”,可能符合您的需求,但我自己从未真正喜欢它,因为可能没有很好的理由。
答案 3 :(得分:2)
我想说这取决于。复制构造的类型有多贵?你能写出你的功能RVO - 友好吗?至少在我们使用rvalue references的C ++ 0x之前,我的建议是不返回“昂贵”类型(例如std::vector<std::string>
),而是将它们作为引用传递,例如使用方法:
void split(const std::string &txt, char sep, std::vector<std::string> &out);
而不是:
std::vector<std::string> split(const std::string &txt, char sep);
根据您编写函数的方式,RVO可能会启动,但根据我的经验,这并不是您通常可以依赖的。
答案 4 :(得分:2)
关于您关于API设计的书的问题。寻找Martin Reddy于2011年发布的“API Design for C ++”。
作为对已接受答案的评论。在本书中,作者实际上建议更喜欢用于输入参数的const引用和用于输出参数的指针,因为它更明确地指示客户端可以修改参数,例如, foo(bar)vs. foo(&amp; bar)。
您也可以观看演讲How To Design A Good API and Why it Matters。其中主要使用Java,但我记得。
答案 5 :(得分:1)
我认为如果某些内容不正确则返回NULL并且如果在这种情况下确定更好则使用SomeStruct
SomeStruct* is_something_ok(int param);
在这种情况下,除了检查布尔值之外,你应该检查它是否为NULL,如果不使用它。
但是有些情况下你必须通过参数返回值。它取决于返回值的数量,并且可以使用上下文函数。
答案 6 :(得分:1)
您可以执行以下操作:
bool is_something_ok(int param,SomeStruct* p);
或
// return NULL if the operation failed.
Somestruct* do_work(int param);
很难说设计/ API是好还是坏,没有什么是黑色或白色......(灰色?!?!?)
您必须选择 更容易编码的API /标准。 是连贯的,如果您选择第一种方法类型,请为项目的其余部分执行此操作。
也不要忘记来记录您的代码,因此了解如何使用您的API会更容易。
答案 7 :(得分:1)
我建议直接返回Result-Type:
SomeStruct doSomething(int param) {...}
并在函数无法处理的情况下抛出异常(tux21b已经以这种方式提到过)。或者,您可以使用std::pair
返回两种类型,而不会抛出异常,如下所示:
pair<SomeStruct, bool> doSomething(int param) {...}
第三,我喜欢将输出参数声明为指针而不是引用(如你所提到的),因为在调用代码中我看到了输入和输出参数的差异。鉴于功能:
void doSomething(const Somestruct& in, Somestruct* out) {...}
然后在调用代码中它是可见的(不看函数声明)输入是什么以及输出参数是什么(如果我最终应用这个概念)。
SomeStruct a;
SomeStruct b;
doSomething(a, &b); // you see a is input, b is output
答案 8 :(得分:0)
如果只想在成功时返回值,则应查看boost::optional
。