如果 null 不是有效值,则使参数成为引用而不是指针
Make argument a reference and not a pointer, if null is not a valid value
据我所知,这是一个很好的规则,如果参数可以合理地为空,则像函数的参数类型这样的指针应该是指针,如果参数永远不应该为空,它应该是一个引用。
基于这个"规则",我天真地期望做类似的事情 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
的行为,因此它是未定义的行为。(这有时被称为"未由省略定义",同样的做法处理不指定对象的左值的许多其他用法)。
如链接页面中所述,未定义的行为不需要任何类型的诊断消息。运行时行为实际上可以是任何东西。编译器可以(但不是必需)生成编译警告或错误。 一般来说,程序员是否遵守语言规则。编译器在一定程度上有所帮助,但它不能涵盖所有情况。
你最好把引用看作是一个方便的指针符号。
它们仍然是指针,运行时错误发生在使用(取消引用)空指针时,而不是在将其传递给函数时。
(引用的另一个优点是,一旦初始化,它们就不能更改为引用其他内容。
- 将const引用参数初始化为默认参数会导致悬空引用吗
- 具有常量引用参数的函数模板专用化
- C++:常量引用参数
- 字符串引用参数的效率C++
- 通过非常量引用参数修改常量引用参数
- 如何将指针变量作为引用参数传递?
- C++初始化 std::function 时如何将占位符绑定到引用/引用参数?
- 移动类的成员作为常量引用参数传递
- C++带有适用于左值和右值的引用参数的函数
- constexpr 函数的常量引用参数:gcc/msvc vs clang/icc
- 如何使用类型特征将函数的通用引用参数限制为 r 值引用?
- 委托构造函数和引用参数
- 对 const 引用参数使用默认值会导致崩溃
- 为什么我们不允许将纯引用参数传递给 std::thread,但允许传递原始指针?
- 为什么我需要将默认引用参数定义为 const 以便为其分配一个左值?
- 将非左值作为常量引用参数传递.临时是在本地作用域还是在调用方作用域中创建的?
- 如何强制函数仅接受左值引用参数
- 模板引用参数推断失败C++
- 非类型引用参数可以在运行时修改,这是否意味着模板可以在运行时实例化?
- 将unique_ptr作为引用参数或常量传递unique_ptr引用