问题场景
假设我们自己实现了一个system函数,用于代替C标准库下面的那个,目的是增强多平台的统一性。Windows实现下的system()1的尿性,大家也是知道的。
思考再三,函数原型如下:
bool system(const std::string& command, int& exitCode);
其中返回值标志是否运行正确,exitCode
引用则负责带回该命令的返回值。
然后遇到了这样一个程序,它的返回值对程序的逻辑无关痛痒,所以可以根本不要这个exitCode
。
解决方案
最脏的办法,就是传一个无用的int
类型变量,调用完后边搁在一边。就算g++
不抱怨unused
,作为强迫症的我们也看不过去这无端多出来的一个无用变量。
很好,接下来有两条路。
使用指针
C语言中也常常有这种情况,这时候我们多半会想到空指针。只要传一个空指针,并在运行时判断是否为NULL
以选择是否写入即可。遂把函数原型改成:
bool system(const std::string& command, int* exitCode);
一切貌似都解决了,指针近乎野蛮地强行为我们开出了一条道路。
但我们是直男癌,阿不,引用癌啊。怎么容许高贵的C++代码里出现指针的身影。
为什么不想想空引用
先看一段标准里的对于引用的说明
A reference shall be initialized to refer to a valid object or function. [Note: in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by dereferencing a null pointer, which causes undefined behavior. As described in 9.6, a reference cannot be bound directly to a bitfield. ]
—ISO/IEC 14882:1998(E), the ISO C++ standard, in section 8.3.2 [dcl.ref]
嗯哼,标准貌似对我们这种意图实现空引用的行为不予支持。在标准中,任何对空引用的操作行为都是未定义行为。但是想想,我们可以通过引用的地址判断其是否有效,于是可以回避这些行为。
判断方法很简单:
if (&ref != nullptr)
//do something
于是我们要开始用奇技淫巧革命了。
创建及使用一个空引用
为了方便创建不同类型的空引用,最好以模板函数的方式实现:
template<typename T>
T& createNullRef() { return *static_cast<T*>(nullptr); }
并以如下方式食用:
system("echo no null ref?", createNullRef<int>());
Voila! 实现方法就是这么简单。
这样真的好么
抛开个人信仰不谈,与标准背道而驰,使用空引用而不是空指针来忽略掉多余的参数,真的是个好方法么?
个人认为,在开发团队都使用这一做法时,这样的方法并没有什么不妥,原因如下:
统一,
system(str1, &exitCode)
与system(str1, exitCode)
相比,后者明显更优。简单,在函数内部只需要几个合法性判断,而不像指针那样需要
*
与->
。C++不就是用来玩的么,这么纠结这一问题为什么不使用golang呢。
我真的很喜欢引用啊。
至少,本弱开发的wTest里使用的就是这一方法。但本人也不知道自己会不会在某一时刻推翻我自己此时的想法。
So,be prudence.
- 在Windows下,system()只是做一个调用其他程序的工作,只要调用成功就返回0,不成功就返回-1,无法通过其获取程序返回值。 ↩