如果 null 不是有效值,则使参数成为引用而不是指针

Make argument a reference and not a pointer, if null is not a valid value

本文关键字:引用 参数 指针 null 有效值 如果      更新时间:2023-10-16

据我所知,这是一个很好的规则,如果参数可以合理地为空,则像函数的参数类型这样的指针应该是指针,如果参数永远不应该为空,它应该是一个引用。

基于这个"规则",我天真地期望做类似的事情 someMethodTakingAnIntReference(*aNullPointer)在尝试进行调用时会失败,但令我惊讶的是,以下代码运行良好,这有点使"规则"变得不那么可用。开发人员仍然可以从引用的参数类型中读取含义,但编译器没有帮助,运行时错误的位置也没有帮助。

我是否误解了这条规则的意义,或者这是未定义的行为,或者......?

int test(int& something1, int& something2)
{
return something2;
}
int main()
{
int* i1 = nullptr;
int* i2 = new int{ 7 };
//this compiles and runs fine returning 7.
//I expected the *i1 to cause an error here where test is called
return test(*i1, *i2); 
}

虽然上述方法有效,但显然以下内容不起作用,但如果引用只是指针,情况也是如此;这意味着规则和编译器并没有真正的帮助。

int test(int& something1, int& something2)
{
return something1+something2;
}
int main()
{
int* i1 = nullptr;
int* i2 = new int{ 7 };

//this compiles and runs returning 7.
//I expected the *i1 to cause an error here where test is called
return test(*i1, *i2); 
}

编写test(*i1, *i2)会导致未定义的行为;特别是部分*i1。这在 C++ 标准中由 [expr.unary.op]/1 涵盖:

一元*运算符执行间接寻址:应用它的表达式应是指向对象类型的指针,或指向函数类型的指针,结果是引用表达式指向的对象或函数的左值。

这仅在X指向对象或函数的情况下定义了*X的行为。 由于i1不指向对象或函数,标准没有定义*i1的行为,因此它是未定义的行为。(这有时被称为"未由省略定义",同样的做法处理不指定对象的左值的许多其他用法)。


如链接页面中所述,未定义的行为不需要任何类型的诊断消息。运行时行为实际上可以是任何东西。编译器可以(但不是必需)生成编译警告或错误。 一般来说,程序员是否遵守语言规则。编译器在一定程度上有所帮助,但它不能涵盖所有情况。

你最好把引用看作是一个方便的指针符号。

它们仍然是指针,运行时错误发生在使用(取消引用)空指针时,而不是在将其传递给函数时。

(引用的另一个优点是,一旦初始化,它们就不能更改为引用其他内容。