本篇文章的关注点是引用作为函数返回值,网上类似很多,具体可参考引用作为函数返回值的优缺点。这里,我想写下自己的想法。
在C++中,引用变量必须要初始化,否则会有编译错误。这里指的初始化,一般变量赋值初始化。如果是通过函数返回值来初始化,那就要好好考虑下。
以获取字体信息场景为例子:在启动时,通过读取字体配置文件来获得字体信息,保存在m_vLogFont。外部通过GetFont接口函数来获得字体信息,每一个Id对于一种字体,接口函数大致实现如下:
const LOGFONT& GetFont(int nFontId)
{
if (nFontId < m_vLogFont.size())
{
return m_vLogFont[nFontId];
}
}
// 外部使用
const LOGFONT& FontInfo = GetFont(FONT_ID);
问题一:通过函数返回值来定义的引用,如何判断其有效性?
按照以往的知识,引用变量一旦初始化,之后就不能再改变。通过函数返回值也算是初始化,在这种情况下,如果引用无效,比如传入一个很大的FontId,在编译阶段是无法发现错误,只有在运行阶段,会报读取访问冲突的错误。
解答:这种情况下,在编译期间是无法判断其有效性的,在运行时可判断。
问题二:如果出现上面的情况,如何预防?
这里有两种解决方案,以GetFont为例子:
-
在if的else分支中,加上ASSERT断言,在调试阶段发现问题。
-
在if的else分支中,加上出错处理,即获取不到,则返回默认字体信息。
这两种处理方式,在实践中都有应用,不同方式对应的场景不一。比如,第二种方式的应用场景是字体配置信息异常。如果不这么做,会因一处配置信息异常,导致整个软件无法运作。
解答:如果产品人员有这方面的需求考虑或者之前有类似情况发生,这种处理方式就是合理的。否则,推荐第一种方式。
小结:工具类函数的返回值需要仔细考虑异常情况,尽量做到异常情况对外部暴露,由外部去处理。同时,此类函数注释撰写要规范,不要注释说明和内部实现不一致,给使用者和后来者挖坑。